Integrating PHP with Windows ®
Arno Hollosi
Published with the authorization of Microsoft Corporation by: O’Reilly Media, Inc. 1005 Gravenstein Highway North Sebastopol, California 95472 Copyright © 2011 by O’Reilly Verlag GmbH All rights reserved. No part of the contents of this book may be reproduced or transmitted in any form or by any means without the written permission of the publisher. ISBN: 978-0-7356-4791-6 123456789 M 654321 Printed and bound in the United States of America. Microsoft Press books are available through booksellers and distributors worldwide. If you need support related to this book, email Microsoft Press Book Support at
[email protected]. Please tell us what you think of this book at http://www.microsoft.com/learning/booksurvey. Microsof t and the trademarks listed at http://www.microsoft.com/about/legal/en/us/ IntellectualProperty/Trademarks/EN-US.aspx are trademarks of the Microsoft group of companies. All other marks are property of their respective owners. The example companies, organizations, products, domain names, email addresses, logos, people, places, and events depicted herein are fictitious. No association with any real company, organization, product, domain name, email address, logo, person, place, or event is intended or should be inferred. This book expresses the author’s views and opinions. The information contained in this book is provided without any express, statutory, or implied warranties. Neither the authors, O’Reilly Media, Inc., Microsoft Corporation, nor its resellers, or distributors will be held liable for any damages caused or alleged to be caused either directly or indirectly by this book. Acquisitions and Developmental Editor: Russell Jones Production Editor: Holly Bauer Editorial Production: Octal Publishing, Inc. Technical Reviewer: Lars Dekenno Copyeditor: Bob Russell Indexer: Julie Hawks Cover Design: Twist Creative • Seattle Cover Composition: Karen Montgomery Illustrator: Robert Romano Author Photo: FH CAMPUS 02/Peter Melbinger
Contents at a Glance Part I
1 2 3 4 5 6 7 8 Part II
Internet Information Services (IIS) Setting Up the Work Environment . . . . . . . . . . . . . . . . . . . . . . . . . . 3 IIS Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Configuring IIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Configuring PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 URL Rewrite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 Error Messages and Error Search . . . . . . . . . . . . . . . . . . . . . . . . . . 185
SQL Server
9 Setting Up SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 Databases and Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 Working with SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 PHP and SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Advanced Database Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Users and Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Part III Active
201 225 253 279 319 343
Directory
15 Setting Up Active Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 LDAP Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Searching in Active Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 Writing in Active Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
365 389 413 451
iii
iv
Contents at a Glance
Part IV Exchange
Server
19 Setting Up Exchange Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479 20 Exchange Web Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491 21 Email and Exchange Web Services Basics . . . . . . . . . . . . . . . . . . . 509 22 Contacts and Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 23 Calendar and Impersonation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559
Table of Contents Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi
Part I
Internet Information Services (IIS)
1 Setting Up the Work Environment . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Setting Up IIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Installing IIS by Using the Server Manager . . . . . . . . . . . . . . . . . . . . . . . . 4 Installing from the Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Setting Up PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Installing PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Available PHP Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Configuring PHP in IIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Configuring PHP by Using the IIS Manager . . . . . . . . . . . . . . . . . . . . . . . 9 Configuring PHP from the Command Line . . . . . . . . . . . . . . . . . . . . . . . 11 Installing by Using the Web Platform Installer . . . . . . . . . . . . . . . . . . . . . . . . 12 Setting Up the Web PI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Setting Up IIS and PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Checking Your PHP Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Backing Up Your Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 A First Sample Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Remote Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2 IIS Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Setting Up a New Site . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 Adding Additional Bindings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Managing the Website . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
What do you think of this book? We want to hear from you! Microsoft is interested in hearing your feedback so we can continually improve our books and learning resources for you. To participate in a brief online survey, please visit:
microsoft.com/learning/booksurvey
v
vi
Table of Contents
Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Paths and Folders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Setting Up a New Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Changing Application Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Virtual Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Setting Up a Virtual Directory by Using IIS Manager . . . . . . . . . . . . . 30 Setting Up a Virtual Directory from the Command Line . . . . . . . . . . . 31 HTTP Request Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Request Flow Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 Application Process Flow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Application Pools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 Setting Up Application Pools by Using IIS Manager . . . . . . . . . . . . . . . 35 Setting Up Application Pools from the Command Line . . . . . . . . . . . . 35 Application Pool Identity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 FastCGI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 FastCGI vs. CGI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 FastCGI vs. ISAPI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
3 Configuring IIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Configuration Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Global Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Distributed Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 Configuration Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Sections and Section Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 Elements and Configuration Listings . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 Moving and Binding Sections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 The Configuration Editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Schema and configSections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 Configuring Paths by Using location . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 Configuring by Using IIS Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 Configuring from the Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . 49 Sites, Applications, and Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 Sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 Applications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 Virtual Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Table of Contents
Locking the Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 Locking with configSections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Locking and Unlocking with location . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 Specifying Rights for Individual Settings . . . . . . . . . . . . . . . . . . . . . . . . 56 Locking and Unlocking by Using IIS Manager . . . . . . . . . . . . . . . . . . . 58 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
4 Configuring PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Installing PHP Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Configuring PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Recognizing Configuration Changes . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Path and Host-Dependent Configuration in php.ini . . . . . . . . . . . . . . 65 Configuring by Using .user.ini . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 Specifying the Default Document . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 Specifying the Default Document by Using the IIS Manager . . . . . . 69 Specifying from the Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 Defining Directly in the Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Request Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Configuring by Using the IIS Manager . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Configuring from the Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 Configuring Directly in the Configuration File . . . . . . . . . . . . . . . . . . . . 73 Time Limits for Request Processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 PHP Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 FastCGI Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 Session Storage and Temporary Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 Setting Up PHP Syntax Highlighting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Configuring Syntax Highlighting by Using the IIS Manager . . . . . . . . 76 Configuring from the Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 Setting Up Different PHP Versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 Installing a New PHP Version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 Configuring by Using the PHP Manager . . . . . . . . . . . . . . . . . . . . . . . . 79 Configuring the Handler Assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 Configuring the FastCGI Application . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 Testing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Setting Up Different PHP Configurations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
vii
viii
Table of Contents
5 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 Structuring the Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 Root Folder or Virtual Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 Specifying the Executable Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 PHP Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 User Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Installing the Required Role Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Setting Up User Authentication by Using IIS Manager . . . . . . . . . . . . . 93 Setting Up User Authentication from the Command Line . . . . . . . . . 94 Windows Authentication and Host Names . . . . . . . . . . . . . . . . . . . . . . 94 Retrieving the Authentication in PHP . . . . . . . . . . . . . . . . . . . . . . . . . . 95 Identity and Access Rights . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 Identity of the Application Pool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 Path Logon Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97 Specifying the Identity of the Anonymous User . . . . . . . . . . . . . . . . . 97 Securing the PHP Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Authorization Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Installing the Required Role Services . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 Defining the Rules by Using IIS Manager . . . . . . . . . . . . . . . . . . . . . . . 99 Defining the Rules from the Command Line . . . . . . . . . . . . . . . . . . . . 100 Request Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 Defining General Settings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 Filtering File Name Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 Filtering with Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 Encrypted Connections (HTTPS) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Creating Keys and Certificates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Setting up an Encrypted Connection . . . . . . . . . . . . . . . . . . . . . . . . . . 110 Authentication with Client Certificates . . . . . . . . . . . . . . . . . . . . . . . . 114 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115
6 Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Caching in the Web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Caching for a Limited Time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 Mutable Contents . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 Caching Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Specifying the Headers with IIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Table of Contents
Output Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 Configuring by Using IIS Manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 Configuring from the Command Line . . . . . . . . . . . . . . . . . . . . . . . . . 128 Configuration Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 The WinCache Extension for PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 Setting Up the WinCache Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . 130 The PHP Opcode and File Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132 Session Handler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 User Cache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
7 URL Rewrite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 Setting Up URL Rewrite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 Installing URL Rewrite Manually . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Installing URL Rewrite by Using the Web PI . . . . . . . . . . . . . . . . . . . . 138 Predefined Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Common Gateway Interface Variables . . . . . . . . . . . . . . . . . . . . . . . . . 139 IIS and PHP Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 Merging PHP Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142 Evaluating Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143 Action Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 Hierarchy and URL Paths . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 Time of the Evaluation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 Setting Up Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 Setting Up Redirect Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146 Setting Up Rewrite Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 Additional Action Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151 Setting Up Rules with Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152 Rewrite Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 Creating a Rewrite Map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 Creating an Associated Rule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 Rules in Detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 Patterns . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156 Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160 Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 Setting Server Variables and HTTP Headers . . . . . . . . . . . . . . . . . . . . 162 Outbound Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 Tag Filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 Creating an Outbound Rule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
ix
x
Table of Contents
XML Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 URL Rewrite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167 Allowed Server Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168 Conditions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169 Server Variables and HTTP Headers . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170 Rewrite Maps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171 Outbound Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 Single Outbound Rule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 User-Friendly URLs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 Canonical Host Name . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 Multilingual Pages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 Canonical User Directories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 177 Preventing the Embedding of Graphics on Foreign Sites . . . . . . . . . 179 Redirecting to HTTPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 Adding a Notice to Each Page . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 Converting from Apache mod_rewrite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
8 Error Messages and Error Search . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Detailed Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Disabling Friendly Error Messages in Internet Explorer . . . . . . . . . . 186 Enabling Detailed Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186 PHP Error Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 188 Tracing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 Installing the Tracing Role Service . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Enabling a Trace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Configuring Logging Rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 Trace Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 PHP Error Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 Outputting to STDERR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 PHP Messages in the Trace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 FastCGI and STDERR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 Determining the Causes of Server Problems . . . . . . . . . . . . . . . . . . . . . . . . 196 The Server Can’t Be Reached . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 PHP Scripts are not Executing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 198
Table of Contents
Part II
SQL Server
9 Setting Up SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 Installing SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 Configuring SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 202 Installing SQL Server Express . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 206 Installing the SQL Server PHP Extension . . . . . . . . . . . . . . . . . . . . . . . 209 SQL Server Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 SQL Server Management Studio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 211 The sqlcmd Command-Line Tool . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 The T-SQL Batch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 Configuring for Remote Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 Enabling the TCP/IP Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 Sharing Access in the Windows Firewall . . . . . . . . . . . . . . . . . . . . . . . 215 Installing the Sample Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 Migrating MySQL Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 Installing the Migration Assistant . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 219 Migrating a MySQL Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 223
10 Databases and Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 System Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 225 Database Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 226 Setting Up Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 Deleting a Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 230 Creating a Snapshot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 Numeric Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 Strings and Binary Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 Dates and Times . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Other Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Schemas and Object Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 Object Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 Creating Schemas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 Deleting Schemas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 Creating Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 Deleting Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243
xi
xii
Table of Contents
Keys and Indexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 Primary Keys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 243 Foreign Keys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 246 Indexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 252
11 Working with SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 Querying Data (SELECT) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 Simple SELECT Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 254 Constraining Queries by Using WHERE . . . . . . . . . . . . . . . . . . . . . . . . 255 Grouping Query Data (GROUP BY, HAVING) . . . . . . . . . . . . . . . . . . . 255 Sorting (ORDER BY) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 256 Queries with Multiple Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 257 Common Table Expressions (WITH) . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 Paging Through Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263 Manipulating Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 The INSERT Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 266 The UPDATE Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 268 The DELETE Command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 271 Querying Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 Listing Databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 274 Listing Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 Retrieving Table Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 276 Listing the Columns of a Table . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277 Listing Constraints . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277 Listing Keys and Indexes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 278
12 PHP and SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 Approach and Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 Preparations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279 The Sample Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280 An Overview of the Individual Steps . . . . . . . . . . . . . . . . . . . . . . . . . . 282 Supporting Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 Database Connections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 Server Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 286 Authentication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 287 Connection Pooling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289 More Connection Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 290
Table of Contents
Database Queries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 Parameterizing Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 291 Retrieving Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297 Prepared Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 299 Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 304 Converting from PHP to SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . 304 Converting from SQL Server to PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . 304 Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 306 PDO and SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 PDO Database Access Lifecycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 310 Connecting to SQL Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311 Direct Queries and Prepared Statements . . . . . . . . . . . . . . . . . . . . . . 311 Retrieving Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 314 Data Types and Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 315 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 317
13 Advanced Database Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319 Full-Text Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 319 Installing the Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 Language Selection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 320 Creating the Catalog and the Index by Using SSMS . . . . . . . . . . . . . 321 Creating the Catalog and the Index by Using T-SQL . . . . . . . . . . . . . 322 Search with Full-Text Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 323 Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 T-SQL Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 326 Transaction Isolation Levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327 PHP Transactions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 328 Transactions Using PHP Data Objects . . . . . . . . . . . . . . . . . . . . . . . . . 330 Stored Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 Defining Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332 Calling Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 Output Parameters and Return Values . . . . . . . . . . . . . . . . . . . . . . . . . 333 Control Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 Calls from PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 Calling Stored Procedures from PDO . . . . . . . . . . . . . . . . . . . . . . . . . . 337 Custom Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 Scalar Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 Table-Valued Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
xiii
xiv
Table of Contents
Triggers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340 Creating a Trigger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340 Detailed Explanation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341 Initiating the Trigger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342
14 Users and Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343 SQL Server Principals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343 Server Principals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343 Database Principals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 344 Creating SQL Server Principals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346 Creating Logins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346 Creating Users . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 Creating Database Roles . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 351 Objects and Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 Managing Permissions by Using SSMS . . . . . . . . . . . . . . . . . . . . . . . . . 355 Managing Permissions by Using T-SQL . . . . . . . . . . . . . . . . . . . . . . . . 356 Stored Procedures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 Security Through Permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 358 Execute as User . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 360 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
Part III Active
Directory
15 Setting Up Active Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365 Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 365 Domains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366 Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367 Installing Active Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367 Preparation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368 Installing the Role . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 368 Installing the Domain Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 370 First Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372 Active Directory Domain Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 372 Organizational Units . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 373 Users . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375 Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377 Setting Up Active Directory Certificate Services . . . . . . . . . . . . . . . . . . . . . 381
Table of Contents
Working with Certificates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 Issuing a Certificate for Active Directory . . . . . . . . . . . . . . . . . . . . . . . 385 Exporting the Root Certificate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 386 Exporting Other Certificates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 387 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 388
16 LDAP Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 LDAP Basics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 389 Hierarchical Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 Classes and Inheritance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 Protocol Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 391 Utilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 392 LDP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 393 ADSI Edit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 Configuring the PHP LDAP Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 Activating the LDAP Extension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 398 Communication Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 399 Supporting Script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 400 Establishing an Encrypted Connection . . . . . . . . . . . . . . . . . . . . . . . . . 401 Authenticating Users . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 403 Querying Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 405 Sample Program: Searching for Domain Users . . . . . . . . . . . . . . . . . . 405 LDAP Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 407 Iterating Through Search Results . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 410 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 412
17 Searching in Active Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413 The PHP LDAP Browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413 Main Program and User Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 413 Formatting an LDAP Entry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 417 Type Information and Search Definitions . . . . . . . . . . . . . . . . . . . . . . 419 Conversion Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 421 The Directory Information Tree and Naming Contexts . . . . . . . . . . . . . . . . 421 Active Directory Schema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422 Object Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422 Attribute Classes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 426 Domain Objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 431 General Attributes for Domain Objects . . . . . . . . . . . . . . . . . . . . . . . . 431 Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 438 Organizational Units . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 440
xv
xvi
Table of Contents
Concrete Search Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 Schema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442 ANR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 444 Users . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445 Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 446 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 450
18 Writing in Active Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 Preparation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 Access Rights . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 451 Error Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 453 Supporting Scripts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455 Writing Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 Adding Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 Deleting Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459 Changing Attributes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 461 Encoding and Character Sets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 462 Practical Examples for Changing Attributes . . . . . . . . . . . . . . . . . . . . . . . . . 463 Unlocking an Account . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 463 Activating and Deactivating Accounts . . . . . . . . . . . . . . . . . . . . . . . . . 464 Group Memberships . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 464 Forced Password Change . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465 Changing Passwords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 466 Writing Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467 Adding New Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 467 Deleting Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 469 Moving Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 470 Practical Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 471 Creating a New Group . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472 Creating a New User . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 472 Deleting a User or a Group . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 474 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 475
Table of Contents
Part IV Exchange
Server
19 Setting Up Exchange Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 479 Setting Up Required Services and Features . . . . . . . . . . . . . . . . . . . . . . . . . 479 General Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480 Configuring IIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 480 Configuring Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481 Configuring Shared Ports . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 481 Installing the Office System Converter . . . . . . . . . . . . . . . . . . . . . . . . 482 Configuring DNS Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482 Installing Exchange Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 482 Configuration After the Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484 Registering Exchange . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 484 Configuring the Exchange Server Certificate . . . . . . . . . . . . . . . . . . . 485 Creating a Mailbox . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 489 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 490
20 Exchange Web Services . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491 Required PHP Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 491 Autodiscover . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 492 How Autodiscover Searches for Configuration Data . . . . . . . . . . . . 492 Configuration Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 493 Retrieving Configuration Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 495 Alternative Methods for URL Queries . . . . . . . . . . . . . . . . . . . . . . . . . 498 SOAP and WSDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499 WSDL Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 499 EWS, WSDL, and PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 500 SOAP Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 501 ExchangeSoapClient Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 502 Using the ExchangeSoapClient Class . . . . . . . . . . . . . . . . . . . . . . . . . . . 504 Information About the Following Chapters . . . . . . . . . . . . . . . . . . . . . . . . . 506 Shorter SOAP Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 Shorter PHP Listings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 506 Object-Oriented Alternative for Parameters . . . . . . . . . . . . . . . . . . . . 507 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 508
xvii
xviii
Table of Contents
21 Email and Exchange Web Services Basics . . . . . . . . . . . . . . . . . . . 509 Structure, IDs, and Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 509 IDs of Labeled Folders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510 Viewing Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510 Selected Properties of Elements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511 Names of Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 511 Finding Folders (FindFolder) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513 Selected Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513 Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 513 Response . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 514 Listing Messages (FindItem) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516 Limiting the Results (Paging) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 516 Sorting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 PHP and Replacement Groups . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 517 Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 519 Response . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 520 Viewing a Message (GetItem) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 522 Requesting the Exchange 2010 Mode Within a SOAP Header . . . . . 523 Defining and Filtering the Message Content . . . . . . . . . . . . . . . . . . . 524 Requesting the Original MIME Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 524 Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 525 Response . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 526 Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 527 Email Attachments (GetAttachment) . . . . . . . . . . . . . . . . . . . . . . . . . . 529 Sending a Message (CreateItem) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 531 SOAP Errors Caused by References and Accessors . . . . . . . . . . . . . . . 531 Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 533 Response . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536 Deleting Messages (DeleteItem) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 536 XML Messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537 PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 537 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 538
22 Contacts and Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 Properties of Contacts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 Standard Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 539 Name Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 541 Properties of Email Addresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 542 Address Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543
Table of Contents
Changing a Contact (UpdateItem) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 543 Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 544 Response . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 547 Finding Certain Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 548 Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 548 Preparation: Modifying the Schema . . . . . . . . . . . . . . . . . . . . . . . . . . . 550 Defining the Search in a Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 552 Complete PHP Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 552 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 558
23 Calendar and Impersonation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559 Calendar Entries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 559 Standard Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 560 Meetings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 Recurring Appointments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 561 Time and Time Zones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 562 Creating a Common Calendar Entry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563 The Request Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 563 The Response Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564 Created Entry . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 564 Meetings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566 Creating a Meeting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566 Creating the Meeting Invitation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 570 Responding to a Meeting Invitation . . . . . . . . . . . . . . . . . . . . . . . . . . . 572 Canceling a Meeting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 577 Appointment Conflicts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 580 The Request Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 580 The Response Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 581 Searching the Calendar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 582 The Request Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 582 The Response Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583 A Complete PHP Example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 583
What do you think of this book? We want to hear from you! Microsoft is interested in hearing your feedback so we can continually improve our books and learning resources for you. To participate in a brief online survey, please visit:
microsoft.com/learning/booksurvey
xix
xx
Table of Contents
Impersonation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587 Granting Impersonation Rights . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 587 Impersonation in EWS Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . 588 Additional Steps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 590 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 591
24 Example Scripts and Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593 The HTMLPage Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 593 The HTML Template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 596 The DatabaseConnection Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 597 Example Database: AdventureWorksLT2008 . . . . . . . . . . . . . . . . . . . . . . . . . 599
Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 601
Introduction PHP has changed the world: no other language has influenced and spurred web development so strongly. From simple home pages to social software and business applications to the largest global websites, PHP has played a leading role for years. Simultaneously, Microsoft and its Windows operating system has made computers available to all households. Along with Internet Information Services (IIS) for Windows Server, Microsoft SQL Server, Microsoft Active Directory, and Microsoft Exchange Server, it has created a solid and powerful platform for organizations and companies, as well. Microsoft recognizes the potential that lies in supporting PHP in its own products, and is now explicitly incorporating PHP into its development strategy, thus promoting interoperability with the Windows platform. Thanks to the recent efforts by the Windows PHP team, including Pierre Joye, Ruslan Yakushev, and others, the combination of IIS and PHP is now faster, more stable, more secure, and easier to manage than ever. These efforts—FastCGI, WinCache, PHP Manager, new drivers for SQL Server, the integration with Microsoft’s Web Platform Installer (Web PI), as well as development aids for Windows Azure, Virtual Earth, Webslices, Silverlight, and SQL Server (just to name a few)—make PHP development on Windows an enjoyable and productive experience. Combined with the ever-improving interoperability of Microsoft’s products, PHP is ready for just about every task in corporate environments. Whether you want to access Exchange Server through its SOAP web services, manage users in Active Directory with Lightweight Directory Access Protocol (LDAP), or use Windows credentials to provide seamless authentication of your users, PHP is up to the task. In addition, Microsoft provides extensive developer documentation on its MSDN developer network and on TechNet, which leaves few common questions unanswered. Also, several of Microsoft’s core PHP developers share valuable insights, tips, and tricks on their blogs. If, like me, you have mostly been using PHP with Apache and MySQL, you should be excited about the functionality, stability, performance, and integrated security architecture of the Microsoft platform. This book shows you how to run your PHP applications effectively and securely with IIS and SQL Server, and how to access user data in Active Directory as well as the calendar and email data in Exchange Server.
xxi
xxii
Introduction
Who Should Read This Book This book exists to introduce PHP developers to Microsoft’s web and database technologies. It is also especially useful for programmers developing applications that interface with Microsoft Active Directory or Microsoft Exchange Server. After reading this book, you will have a deep understanding of how PHP interacts with IIS so that you can tweak your configuration for optimal security and performance. You will know how to access SQL Server, which authentication model is best suited for your needs, how to perform full-text searches, and how to interface with stored procedures. You will be able to access Active Directory to manage users and groups, or use it for authentication purposes. And finally, you will be able to use Exchange Web Services (EWS) to read and write emails, organize meetings, and manage your calendar.
Assumptions This book assumes that you already have some experience in developing PHP applications and accessing relational database systems (for example, with Apache and MySQL). You should also be familiar with basic web concepts, such as the HTTP request/response cycle, and be familiar with the concepts of the relational database model, such as tables and rows, and have dabbled in SQL. In addition, this book assumes that you have a basic understanding of XML, because XML is used for configuration files and Exchange Server’s SOAP web services. Although this book describes the necessary steps to set up IIS, SQL Server, Active Directory, and Exchange Server, as well as the necessary steps to follow the given examples, it is not by any means a comprehensive description of these products. Therefore, you should have a minimal understanding of the purpose and function of these systems.
Who Should Not Read This Book Not every book is aimed at every possible audience. If you have no prior experience with PHP or database systems, you might have a hard time following the explanations. Also, if you expect a complete introduction to Active Directory or Exchange Server, you might be disappointed—there’s simply not enough room in a single book.
Introduction
xxiii
Organization of This Book This book introduces you to programming IIS, SQL Server, Active Directory, and Exchange Server. In each section, you will learn how to set up your development environment, the basic architecture and inner workings of these systems, and how to implement common tasks in PHP. Example configurations and listings illustrate each point and help you to improve your understanding and achieve your goals. This book attempts to lower the entry barrier for programming these systems as well as to thoroughly prepare you for further exploration of Microsoft’s ecosystem. This book is divided into four sections that roughly correspond to the technologies discussed. Depending on your interest or prior knowledge, you can jump directly to any section. The four sections are: ■
Part I, “Internet Information Services (IIS)” This part discusses how PHP can be integrated into IIS and how IIS processes a request. You will gain a solid understanding of how to configure IIS and how it operates. This part is especially useful if you are switching to IIS from another web server. The chapters in this part discuss how to secure your PHP applications against attacks, how to use caching to dramatically increase the performance of your application, and how you can use URL Rewrite to create user-friendly URLs.
■
Part II, “SQL Server” This part shows how to interface PHP programs with SQL Server, or, to be more precise, SQL Server’s database engine. You will learn how to create databases and tables and how to manage access rights. Because SQL Server uses a flavor of SQL called Transact-SQL (T-SQL), this part describes the T-SQL syntax and commands. Next you’ll dive into using the native PHP driver for SQL Server, using it for tasks that range from reading the results of simple SQL SELECT statements to dealing with stored procedures and converting data types between SQL Server and PHP. This part also covers accessing SQL Server via PHP Data Objects (PDO), and the differences between PDO and the native driver. You’ll also look at how to set up full-text search in the database, which is a common requirement of web applications.
■
Part III, “Active Directory” After introducing the general concepts of Active Directory, domains, and forests, this part explains the hierarchical data structure in detail, introducing important objects and attributes and visualizing them by way of a PHP LDAP browser that you’ll develop as an example application. Other chapters in this part describe how you can search for and authenticate users and other principals by using LDAP, and how you can modify user attributes, manage their group memberships, create new users, and reset their passwords.
xxiv
Introduction ■
Part IV, “Exchange Server” Accessing Exchange through its SOAP web service interface is the focus of this part. Each chapter focuses on one aspect, such as sending and reading email, searching for contacts in the address book, creating calendar entries, or accepting and denying meeting invitations. In each chapter, you’ll also learn additional options and interface methods. This part contains valuable tips and tricks on how to coax PHP and Exchange to work together and helps you overcome the initial hurdles.
Conventions and Features in This Book This book presents information using conventions designed to make the information readable and easy to follow. ■
Each exercise consists of a series of tasks, presented as numbered steps (1, 2, and so on) listing each action that you must take to complete the exercise.
■
Boxed elements with labels such as “Note” provide additional information or alternative methods for completing a step successfully.
■
Text that you type (apart from code blocks) appears in bold type.
■
A plus sign (+) between two key names means that you must press those keys at the same time. For example, “Press Alt+Tab” means that you hold down the Alt key while you press the Tab key.
■
A vertical bar between two or more menu items (for example, File | Close) means that you should select the first menu or menu item, and then the next, and so on.
System Requirements You will need the following hardware and software to complete the practice exercises in this book: ■
Either Windows 7 or Windows Server 2008 R2. For Exchange Server, you need the 64-bit version of Windows Server 2008 R2.
■
SQL Server 2008 R2 (Express Edition or higher), with SQL Server Management Studio (Express Edition or higher).
■
Exchange Server 2010 (or 2010 SP1).
■
A computer that has a reasonably fast processor (2 GHz recommended); a 64-bit processer for Exchange Server.
Introduction
xxv
■
2 GB RAM for running IIS, SQL Server, and Active Directory in a development environment; another 4 GB RAM for Exchange Server.
■
3.5 GB of available hard disk space.
■
An Internet connection to download software or chapter examples.
You will require Local Administrator rights for installation and configuration of the server systems; for Active Directory, you will require Domain Administrator rights.
Code Samples Most of the chapters in this book include exercises that let you interactively try out new material learned in the main text. All sample projects, in both their pre-exercise and postexercise formats, can be downloaded from the following page: http://go.microsoft.com/FWLink/?Linkid=229620 Follow the instructions to download the PHP_sample_code.zip file.
Installing the Code Samples Follow these steps to install the code samples on your computer so that you can use them with the exercises in this book.
1. Unzip the PHP_sample_code.zip file that you downloaded from the book’s website (name a specific directory along with directions to create it, if necessary).
2. If prompted, review the displayed end-user license agreement. If you accept the terms, select the accept option, and then click Next. Note If the license agreement doesn’t appear, you can access it from the same webpage from which you downloaded the PHP_sample_code.zip file.
xxvi
Introduction
Using the Code Samples The folder created by extracting the zip file contains two subfolders. ■
Listings This folder contains all of the listings sorted by chapter, as they appear in the book. The listings are UTF-8 encoded, without a byte-order mark (BOM) at the beginning. The filename suffix indicates the content: *.php PHP script or PHP code snippet
●
*.sql T-SQL script
●
*.xml IIS configuration or EWS SOAP message
●
■
EWS This folder contains the modified WSDL definition of Exchange Web Services 2010 SP1. The modifications are necessary for PHP and Exchange to work together and are discussed in Chapters 19 to 23.
You should be able to use the provided examples as is, but sometimes you will need to adjust the configuration for your own development environment. When the book creates and adds to PHP files in a step-by-step fashion as part of an exercise (most notably the LDAP browser in Chapter 17, “Searching in Active Directory”), the listings also contain PHP files that incorporate all the edits. Note that PHP files are referenced by other scripts without the chapter and listing number (just as they appear in the book). So you should either rename the files to be included or change the include/require statement accordingly. Also, many of the examples require the listings from Appendix A, “Example Scripts and Data,” to be in the include path: either include this directory in the PHP include path or just copy the files into the directory, where the script you would like to run resides.
Acknowledgments To write a book, authors need a supportive and motivating environment. At O’Reilly Media, I would like to thank my editor Russell Jones, along with Holly Bauer and Christie Rears, and Dianne Russell at Octal Publishing for their great help and teamwork; Brigitte Possin and Angela Walwick, for the skilled and seamless translation of the text from its original German to English; Christian Wenz, for his knowledgeable technical editing; Lars Denneko and Daniel Chapman, technical reviewers for the English translation; Manfred Steyer, for inciting me to write this book; Agnes Krispel, Julia Egger, and my colleagues at FH CAMPUS 02 for providing a comfortable and inspiring working environment; the teachers and mentors who have accompanied me on my journey; my long-time friends Doris “Donnerdackel” Leipold and Anton Huber; and my family, without whose support I can’t imagine living my life. Dad, this one is for you. Graz, September 2011 —Arno Hollosi
Introduction
xxvii
Errata & Book Support We’ve made every effort to ensure the accuracy of this book and its companion content. Any errors that have been reported since this book was published are listed on our Microsoft Press site at oreilly.com: http://go.microsoft.com/FWLink/?Linkid=229618 If you find an error that is not already listed, you can report it to us through the same page. If you need additional support, email Microsoft Press Book Support at
[email protected]. Please note that product support for Microsoft software is not offered through the addresses above.
We Want to Hear from You At Microsoft Press, your satisfaction is our top priority, and your feedback our most valuable asset. Please tell us what you think of this book at: http://www.microsoft.com/learning/booksurvey The survey is short, and we read every one of your comments and ideas. Thanks in advance for your input!
Stay in Touch Let’s keep the conversation going! We’re on Twitter: http://twitter.com/MicrosoftPress.
Contacting the Author PHP, Windows, and accompanying technologies are constantly being developed and improved. If you have ideas or remarks that you would like to share, or have had noteworthy experiences while programming Microsoft technologies with PHP, I would like to hear from you. Criticism is welcome, as well. You can reach me by email at
[email protected]. Additional information can be found on my website at http://xmp.net/php/.
Part I
Internet Information Services (IIS) In this Part: Chapter 1 Setting up the Work Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Chapter 2 IIS Architecture . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Chapter 3 Configuring IIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Chapter 4 Configuring PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 Chapter 5 Security . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 Chapter 6 Caching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Chapter 7 URL Rewrite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 Chapter 8 Error Messages and Error Search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
1
Chapter 1
Setting Up the Work Environment In this chapter: Setting Up IIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Setting Up PHP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Configuring PHP in IIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 Installing by Using the Web Platform Installer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 Backing Up Your Configuration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 A First Sample Application . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Remote Access . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
This chapter describes how to set up your work environment, which consists of PHP and the Internet Information Services (IIS) web server. Initially, you will install only the essential components to keep resource use to a minimum and limit attack surfaces. The examples in this book use the versions of the individual components that were current at the time of printing (October, 2011); these include PHP 5.3.8 and IIS 7 (version 7.5). The operating systems (OS) are Windows Server 2008 R2 SP1 and Windows 7 Ultimate SP1. The descriptions should (in slightly modified form) also work for other Windows OS versions. IIS 6, although still widely used, is not covered in this book. The differences between IIS 6 and IIS 7 are significant. IIS 7 provides many new features that are especially pertinent to PHP programmers—and these features are not available in IIS 6. Furthermore, the configuration has been changed radically, so descriptions that apply to IIS 7 cannot be applied to IIS 6. The following sections first describe the process to set up IIS 7, then PHP, and then the installation of PHP on IIS. You’ll cover the installation with the help of the Windows Management Tools as well as how to set it up by using the command line. The latter is especially interesting for advanced users. Finally, you’ll see how to perform the installation via the Microsoft Web Platform Installer, which automates many of the manual configuration steps.
3
4
Part I Internet Information Services (IIS)
Setting Up IIS The current version of IIS has a modular design that ensures a fine granularity of selectable features that support a wide variety of usage scenarios. You only need to install the modules required for your particular usage scenario; thus, can use these features to customize IIS according to your requirements to save system resources. Furthermore, a server configured in this fashion provides a smaller attack surface, and therefore, improved security against attacks from the Internet. You can install IIS in several different ways. The following sections explore the installation procedure using both Server Manager and via the command prompt. You can also install IIS via the command prompt on the Windows Server 2008 R2 Core edition. The installation described here adds only the Common Gateway Interface (CGI) Role Service, which is required to run PHP with IIS. You can install other role services if you need them. Later chapters will indicate when you need to install additional features.
Installing IIS by Using the Server Manager If you are using the Server Manager for installation, perform the following steps, which will start a wizard that takes you through the individual IIS installation steps.
1. Start the Server Manager by clicking the Start menu, and then clicking All Programs | Administrative Tools | Server Manager.
2. Select Roles | Add Roles. The Add Roles Wizard opens. Confirm the Before You Begin page by clicking Next.
3. On the Server Roles page, choose Web Server (IIS), and then click Next.
4. Click Next to confirm the Web Server (IIS) page.
5. On the Select Role Services page, select the Web Server (IIS) option. In the Application Development section, select the CGI check box (see Figure 1-1), and then click Next.
Chapter 1 Setting Up the Work Environment
Figure 1-1 Adding the CGI role service to IIS.
6. Click Install to confirm your choices and begin the installation.
7. After the installation completes, click Close to complete the wizard. You have now successfully installed IIS. You don’t need to restart Windows. You can check whether the installation of IIS was successful by starting a web browser and opening the website http://localhost/. The default website with the welcome text will be displayed.
5
6
Part I Internet Information Services (IIS)
Installing from the Command Line To install IIS from the command line, you need the pkgmgr.exe tool, which is a new commandline tool that ships with Windows Server 2008 for managing optional Windows features. It replaces the older sysocmgr.exe tool. Important You need administrator rights to perform this procedure. By default under Windows Server 2008, only the integrated administrator account has these rights. Other user accounts do not—even if they belong to the administrator group.
1. Open a command prompt window with administrator rights. You can find the command prompt in your Start menu by clicking All Programs | Accessories | Command Prompt, or you can launch it via the Start menu by typing cmd in the Search Programs And Files text field.
2. With the command prompt open, enter the following command to install the IIS Server Role and the CGI Role Service: pkgmgr /iu:IIS-WebServerRole;IIS-CGI
3. Ensure that the installation completed without errors by entering: echo %errorlevel%
You have now successfully installed IIS via the command prompt. You can check whether the installation of IIS was successful by starting a web browser and opening the website http://localhost/. You’ll see the IIS default website containing some welcome text.
Setting Up PHP After you have successfully installed IIS, you can install PHP and configure it for use with IIS. Again, you’ll see how to configure PHP via the IIS Manager application as well as from the command line. Only experienced users should use the command-line version; typically you’d use it when there’s no graphic interface (such as under Windows Server 2008 R2 Core edition) or when you want to automate the installation with a script.
Installing PHP
1. In Internet Explorer or another browser, open the website http://windows.php.net/ download/.
2. Download the current PHP version 5.3.x (as of this book’s printing, the latest version is 5.3.8) as a zip file. Choose the zip file from the VC9 x86 Non Thread Safe download section.
Chapter 1 Setting Up the Work Environment
7
3. Create a C:\PHP folder, and then extract the zip file to that folder. You can actually unzip the files anywhere you like, but this book uses the folder C:\PHP, so following the examples will be easiest if your location folder matches this.
4. Copy the file C:\PHP\php.ini-development to C:\PHP\php.ini.
5. Open the file C:\PHP\php.ini with a text editor such as NotePad.
6. Look for the line that configures the date.timezone, and set the value to your local time zone, for example: date.timezone = “America/Los_Angeles”.
7. Set the option cgi.force_redirect = 0. Note You also set the option fastcgi.impersonate=1, but for now you can skip this op-
tion. It controls which account IIS uses to execute PHP code. You’ll see more details later in Chapter 5, “Security,” in the section “Identity and Access Rights.”
8. To check whether your installation was successful, open a command prompt window, browse to the folder C:\PHP, and then run the command php –c C:\PHP –info. PHP will list all its settings and configuration data, as shown in Figure 1-2.
Figure 1-2 Output following the successful installation of PHP.
Important If you receive an error message about an invalid side-by-side configuration, your system is missing the Visual C++ runtime component libraries that correspond to the PHP version. If that happens, download the Microsoft Visual C++ 2008 SP1 Redistributable Package (x86) from MSDN (you can find a link in the left bar on the PHP download page), and then install it on your system.
8
Part I Internet Information Services (IIS)
Available PHP Modules Your PHP installation is now complete. The precompiled PHP installation files provided on http://windows.php.net/ contain all the default PHP modules as well as some optional extensions. After installation, you can check the list of compiled modules by typing the command php –m at the command prompt in your C:\PHP folder. You’ll find additional modules that can be dynamically loaded when you launch PHP in the folder C:\PHP\ext. To activate these modules, you must configure PHP to load and activate them in the php.ini file. Note This book alerts you whenever you need to configure any of the dynamic modules to follow the examples.
Configuring PHP in IIS Now that PHP is installed on your computer, you need to configure IIS to use PHP to process requested PHP pages. You configure PHP as a handler in IIS. Because of the modular structure of IIS, you can specify different programs (handlers) to process different types of content. The basic IIS installation sets up three handlers: the specific handlers for the HTTP methods, OPTIONS and TRACE, as well as the StaticFile handler, whose only task is to return an existing requested local file without changing it. Note Handlers are only a link in the IIS chain of commands for processing an incoming
HTTP request. You will find a more detailed illustration of the complete chain in Chapter 2, “IIS Architecture.”
By default, IIS simply uses the StaticFile handler to return requested files that have a .php extension. However, when you configure PHP as a handler, files with the extension .php are no longer delivered directly and unmodified, but are executed by the PHP Interpreter, and the result is sent back to the browser. For now you’ll perform only the minimal configuration required to run PHP programs. Chapter 3, “Configuring IIS,” contains a more detailed description of other important configurations, particularly with regard to performance and security.
Chapter 1 Setting Up the Work Environment
9
Configuring PHP by Using the IIS Manager To configure PHP by using the IIS Manager, perform the following procedure:
1. Start the IIS Manager. You can do this via the Server Manager application by clicking Server Manager | Roles | Web Server (IIS) | Internet Information Services (IIS) Manager, or via the Windows Start menu by typing inetmgr in the Search Program And Files text box.
2. On the server level, open the Handler Mappings item, as shown in Figure 1-3.
Figure 1-3 Selecting the handler mappings in the IIS Manager.
3. In the right column, select the action Add Module Mapping.
4. Set the values to those shown in Figure 1-4. The request path should include all files with the PHP extension (*.php). Select FastCgiModule for the module, and php-cgi.exe for the executable file. You can choose any name you like.
10
Part I Internet Information Services (IIS)
Figure 1-4 Module assignment of PHP in IIS.
5. Click the Request Restrictions button.
6. On the Mapping tab, select the Invoke Handler Only If Request Is Mapped To check box, and then select the File option.
7. On the Verbs tab, you can optionally set restrictions for the HTTP assignment methods (for example, restrict to the methods HEAD, GET, and POST).
8. Click OK to close the Request Restrictions dialog box.
9. Click OK to confirm your choices.
10. Click Yes to confirm the module mapping. This enables IIS to run PHP as a FastCGI application.
11. In the web server’s root folder (C:\inetpub\wwwroot\), create the file phpinfo.php with the following content:
12. Start a web browser, and then browse to the address http://localhost/phpinfo.php. The response contains the phpinfo() information with the current PHP settings, as shown in Figure 1-5. Important If, instead of getting the phpinfo() page, you receive a server error “500—
Internal server error,” perform an error search as described in Chapter 8, “Error Messages and Error Search.”
Chapter 1 Setting Up the Work Environment
11
Figure 1-5 The phpinfo() output after successfully setting up PHP.
Configuring PHP from the Command Line To configure IIS from the command line, you use the new IIS 7 command-line program appcmd, which is located in the C:\Windows\System32\inetsrv folder. By default, this folder is not in the Windows search path, so to launch the program, you must either browse to the folder and then open a command prompt, or enter the complete program path at the command prompt, or add the path to the PATH environment variable for your Windows installation. Here’s the procedure to configure PHP from the command line:
1. Open a command prompt window with administrator rights.
2. Configure the FastCGI application pool by typing the following command: appcmd set config /section:system.webServer/fastCGI /+[fullPath='C:\PHP\php-cgi.exe']
3. To configure the handler assignment, run the following command: appcmd set config /section:system.webServer/handlers /+[name='PHP_via_FastCGI', modules='FastCgiModule',scriptProcessor='C:\PHP\php-cgi.exe', verb='*',path='*.php',resourceType='File']
12
Part I Internet Information Services (IIS)
Important Due to space restrictions, the preceding command is shown on multiple lines. However, when you type the command, you must be sure to enter the configuration parameters on a single line.
4. In the web server’s root folder (C:\inetpub\wwwroot\), create the file phpinfo.php with the following content:
5. Start a web browser, and then browse to the address http://localhost/phpinfo.php. You should see the phpinfo() page with the current PHP settings.
Installing by Using the Web Platform Installer A simple alternative to the previously described methods for setting up your PHP and IIS work environment is to use the Microsoft Web Platform Installer (Web PI). Web PI bundles many of the manual steps you’ve just seen into a fully automatic installation. By installing the Windows Web App Gallery, Web PI also offers automatic installation of a number of other supported applications, such as the blog software WordPress, or the content management system Joomla!. Web PI is therefore perfectly suited for getting started with PHP under Windows, quickly and easily. The following section describes how to install on a Windows 7 Ultimate SP1 OS. However, you can also use Web PI with Windows Vista, Windows XP SP2+, Windows Server 2003 SP1+, and Windows Server 2008. The steps are similar and should be easy to follow on these other systems.
Setting Up the Web PI The Web PI is itself a program, so you need to install it first by performing the following steps.
1. Open the website http://www.microsoft.com/web/downloads/platform.aspx.
2. Download the Web PI and save the installation file wpilauncher_3_10.exe locally. The Web PI version used in this book is 3.0.
3. Run the installation file wpilauncher_3_10.exe. If you are not logged on as an administrator, confirm the User Account Control dialog by clicking Yes, to permit the installation to execute.
4. After a successful installation, you’ll see the start window of the Web PI.
Chapter 1 Setting Up the Work Environment
13
Setting Up IIS and PHP With the Web PI configured, you can now set up the web server by performing the following:
1. Start the Web PI.
2. Click Products at the top. Add IIS 7 Recommended Configuration, IIS: CGI, and PHP Manager For IIS by clicking the respective Add buttons, as shown in Figure 1-6.
Figure 1-6 Selecting the web server options in the Web PI.
3. Click the Install button.
4. In the Web PI dialog box that appears, click the I Accept button. The Web PI now starts to download and install all the selected (and required) components—this process can take a few minutes.
5. When the installation is complete, click the Finish button.
6. Click the Exit button to close the Web PI.
7. Start a web browser, and then open the webpage http://localhost/. You should see the IIS welcome page.
14
Part I Internet Information Services (IIS)
Note Microsoft also provides a complete web development environment called WebMatrix.
This is a very nice tool that is quick and easy to deploy, but it has limited configuration options. This is why we do not use WebMatrix for the examples in this book.
Checking Your PHP Installation Just as with the other installation methods, it’s a good idea to ensure that your PHP installation was successful by performing the following procedure:
1. In the web server’s root folder (C:\inetpub\wwwroot\), create a file called phpinfo.php with the following content:
Note If you don’t have sufficient rights to create a file in the root web folder, open
Windows Explorer, select the folder C:\inetpub\wwwroot, and then from the context menu, select Properties | Security | Edit. In the ensuing dialog box, you can set the permissions appropriately for your user account.
2. Start a web browser, and then browse to the address http://localhost/phpinfo.php. The resulting webpage displays the phpinfo() information with the current PHP settings.
Backing Up Your Configuration After successfully installing IIS and PHP, you should definitely back up the data of your server configuration. IIS stores configuration data in the C:\Windows\System32\inetsrv\config folder, in three files: applicationHost.config, administration.config, and redirection.config. You can back up the entire folder manually, but alternatively, you can use the command line appcmd tool to create a backup copy of all essential configuration files by typing appcmd add backup "MyBackup". This command creates a backup copy of the current configuration in the folder C:\Windows\ System32\inetsrv\backup\MyBackup. Note In Windows 7, you need to run appcmd in a command prompt with administrator rights.
Select Start | All Programs | Accessories | Command Prompt, right-click it, and then from the context menu, execute the command Run As Administrator.
You should create a backup copy of the current configuration after each modification, especially after you install new modules or components. By doing that, you can reset the configuration back to a defined state, if necessary.
Chapter 1 Setting Up the Work Environment
15
A First Sample Application After completing the IIS and PHP configurations as described in the preceding sections, you’re ready to begin writing and using PHP applications. Before getting into more advanced configuration options in the next chapters, you can use the basic configuration you just completed to run your first sample application. This exercise serves to show that you can run and use PHP features such as forms and sessions as expected in the basic configuration. This example creates a simple PHP application that guesses a random number between 1 and 100. Figure 1-7 shows the start page of the PHP application, and you can see the program code in Listing 1-1. When the session first starts, if no random number is set, the application generates one, and saves it in the session variable $_SESSION['number']. When a user enters a number (the variable $_POST['guessed']), the program compares it to the stored number to be guessed and display and appropriate message. The game ends when the user guesses the correct number. The program then calls the function startGame() to start a new game. Listing 1-1 A PHP example application to guess a number between 1 and 100. Guessing Numbers Doris D. Lass /o=XMP/ou=Exchange Administrative Group (FYDIBOHF23SPDLT) /cn=Recipients/cn=Doris D. Lass 2a4df4d0-8bd0-487d-abc5-1cc233d5500e email settings EXCH DOCO-EXCH.xmp.site /o=XMP/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Configuration /cn=Servers/cn=DOCO-EXCH ... https://doco-exch.xmp.site/EWS/Exchange.asmx https://doco-exch.xmp.site/EWS/Exchange.asmx ... WEB https://doco-exch.xmp.site/owa/ EXCH https://doco-exch.xmp.site/EWS/Exchange.asmx https://mail.phpdemo.site/owa/ EXPR https://mail.phpdemo.site/ews/exchange.asmx
Chapter 20 Exchange Web Services
495
Note For a description of all elements in the POX Autodiscover response, go to MSDN at http://msdn.microsoft.com/en-us/library/bb204082.aspx
Retrieving Configuration Data The Autodiscover service requires NTLM authentication (Exchange default configuration). You can choose any user with read access to the associated entries in Active Directory. The searched email address is passed in an XML structure and sent over HTTP POST to the Autodiscover URL. The following function assumes that the URL is an HTTPS URL with NTLM authentication. HTTP redirection or SVR entries are not considered.
Query with cURL Listing 20-2 shows how you use the cURL PHP extension to retrieve the configuration data: ■
First the XML request ($request) is generated. Caution The URL of the AcceptableResponseSchema element cannot contain spaces or line breaks.
■
curl_setopt_array() configures the parameters for the connection. Important are CURLOPT_HTTPAUTH, CURLOPT_USERPWD and CURLOPT_CAINFO: the first two parameters contain the information for the NTLM authentication, and the last parameter contains information on the HTTPS certificate. The XML request is passed in CURLOPT_POSTFIELDS.
■
curl_exec() sends the HTTP request and returns the response to the caller.
Note This function doesn’t include error queries (curl_error() or curl_getinfo()) and doesn’t
evaluate the XML, which can contain an error message. You should consider these facts in a production environment.
496
Part IV Exchange Server Listing 20-2 autodiscover.php—retrieving the Autodiscover data over TLS with NTLM authentication.
The path passed with CURLOPT_CAINFO has to point to the base-64–encoded (PEM, CER) root certificate of the certification authority (CA) issuing the HTTPS certificate for Exchange. If the CA is a third-party CA, download the root certificate from its website and save it on a local drive.
Chapter 20 Exchange Web Services
497
If you use your own CA operated with the Active Directory Certificate Services, you can export the root certificate by using the Microsoft Management Console (MMC). You can also use Microsoft Internet Explorer to export the root certificate to a domain computer. To do so, click the Tools icon, and then select Internet Options. On the Content tab, click the Certificates button, and then click the Trusted Root Certification Authorities tab. The CURLOPT_SSL_VERIFYHOST option specifies whether the Exchange domain name must be included in the certificate: The recommended value (2) checks whether the name in the certificate matches the host name.
Evaluating Configuration Data Listing 20-3 shows how the SimpleXML PHP extension and the built-in XPath support is used to retrieve the EWS URLs. In the listing, the URLs are retrieved with two XPath expressions. The search returns an array of URLs for EWS connections because in larger Exchange installations, multiple URLs can be specified. The scripts returns only the first internal and external URL (Index 0). Listing 20-3 Retrieving the internal and external EWS URLs.
If you are getting errors, first try to open the Autodiscover URL with a web browser to verify that you can reach the address and that your credentials are correct. If you make it to the error message “600 Invalid Request”, the URL and credentials are fine. Next, you can get additional error information from cURL by calling curl_error() and enabling the CURLOPT_ HEADER and CURLINFO_HEADER_OUT options. Print the response of curl_exec(). Exchange is picky about the content type, even spaces can throw it off.
498
Part IV Exchange Server
Alternative Methods for URL Queries You can also retrieve the Autodiscovery and EWS URLs in Active Directory or by using the Exchange Management Shell.
Active Directory Exchange saves a service connection point (SCP) in the naming context (CN=Configuration, DC=…,DC=…) of Active Directory. The entries for servers providing Autodiscover functions are saved in CN=Autodiscover, CN=Protocols,CN=,CN=Servers,CN=Exchange Administrative Group (), CN=Administrative Groups,CN=,CN=Microsoft Exchange, CN=Services. The serviceBindingInformation attribute contains the internal Autodiscover URL. Note The Autodiscover URL is an intranet URL, because Active Directory is only accessible from within a domain.
The entry CN=EWS (Default Web Site),CN=HTTP,CN=Protocols,CN=,CN=Servers, CN=Exchange Administrative Group (),CN=Administrative Groups,CN=, CN= Microsoft Exchange,CN=Services contains the EWS URLs in the msExchExternalHost Name and msExchInternalHostName attributes.
Exchange Management Shell In Exchange Management Shell (EMS), you can query the information in Active Directory by using the following cmdlets: ■
Get-clientAccessServer The AutoDiscoverServiceInternalUri property contains the internal Autodiscover URL.
■
Get-WebServicesVirtualDirectory The InternalUrl and ExternalUrl properties contain the URLs for the EWS services.
■
Get-AutodiscoverVirtualDirectory Contains information on the IIS virtual directory used for Autodiscover.
To list the properties, use the Format-List cmdlet, as follows: Get-clientAccessServer | fl
You can also set the properties by using Set-clientAccessServer and Set-WebServicesVirtual Directory. Use the parameter -? to get help for these functions.
Chapter 20 Exchange Web Services
499
SOAP and WSDL Now that you know the URL for the EWS, you can send SOAP messages to this URL. SOAP is an XML-based protocol that ensures a structured data exchange. The WSDL definition contains information on the structure and syntax of messages. The PHP SOAP extension parses the WSDL definitions to simplify web services programming. Instead of processing the raw XML SOAP messages, the PHP Soap extension handles the SOAP message content in the same way as PHP objects or arrays.
WSDL Structure WSDL defines the structure and syntax for SOAP messages, based on the following: ■
Message A messages defines the elements of a SOAP request or a SOAP response.
■
Operation An operation consists of a request message (input) and a response message (output).
■
Endpoints (portType) An endpoint combines all operations available at this endpoint. EWS only uses a single endpoint.
■
Binding The binding specifies how the elements of a messages are transferred—for example, in the SOAP header or in the SOAP message body—as well as the SoapAction for the transfer over HTTP.
■
Service The service definition links an endpoint and a binding and specifies the URL for the service.
The message elements are not defined in WSDL but are included in XML Schema files. XML Schema is a syntax description language that defines the content and structure of XML elements and attributes: ■
Values can be strings, numbers, Boolean expressions, data types, enumeration types, and other types.
■
The value range can be limited; for example, you can limit the length of a string or the maximum value of a number.
■
The structure of nested elements can be defined. To specify a sequence of elements you can use sequence, and choice to specify several elements.
■
The number of elements can be specified by using minOccurs (Minimum) and maxOcccurs (Maximum).
■
You can use definition inheritance to derive extended or restricted types from existing types.
EWS defines the message elements in two different files: one file for the message structure (messages.xsd), and one file for the data types (types.xsd) that comprise the message.
500
Part IV Exchange Server
EWS, WSDL, and PHP Because Exchange allows variable EWS URLs, or the URL depends on internal and external host names, the EWS WSDL definition doesn’t include a service definition. This is in line with the WSDL standard but the PHP SOAP extension cannot process WSDL without service definition. To program using WSDL support, you need to download the WSDL file and the associated XML schema files, save the files on a local drive, and then insert the service definition. Because the WSDL definition only changes if a new version of Exchange Server is installed this is a reasonable if not necessarily elegant alternative.
Adding the Service Definition For PHP to work with EWS WSDL, perform the following steps:
1. Download the EWS WSDL file from https:///EWS/Services.wsdl and save the file on your local drive.
2. Download both XML schema files from https:///EWS/Messages.xsd and https:///EWS/Types.xsd. Save the files in the same directory as Services.wsdl. Note You can also find the three files on the Exchange Server. From the Exchange Management Shell, run the following cmdlet:
Get-WebServicesVirtualDirectory | fl Path
By default, the specified directory C:\Program Files\Microsoft\Exchange Server\V14\ ClientAccess\exchweb\EWS) contains the files.
3. Open Services.wsdl in an editor, and then insert the following definition at the end, just before the end tag (replace #EWS-URL# with your EWS URL):
4. Save the file.
Chapter 20 Exchange Web Services
501
Note You can change the EWS URL at a later point in the PHP program while instantiating the SoapClient class (location parameter).
Testing the Modified EWS WSDL File Run the test program in Listing 20-4 to confirm that your modifications were successful. For Exchange Server 2010, more than 50 functions and almost 550 data types are listed. Listing 20-4 test-wsdl.php—functions and data types of the EWS WSDL definition.
Important Because parsing WSDL files and the associated schema files is resource-intensive, PHP caches the results. However, for the test in Listing 20-4, caching is disabled. Based on your requirements, you can also set the configuration parameters soap.wsdl_cache_enabled or soap .wsdl_cache_ttl using the php.ini file or the ini_set() function. In a production environment, caching should be enabled.
SOAP Messages With the prepared WSDL file, you can start programming the Exchange Web Services. However, you cannot use the SoapClient class of the PHP SOAP extension because this class doesn’t provide NTLM authentication for SOAP requests. For this reason, the defined ExchangeSoapClient class is used. This class also uses the PHP cURL extension to send requests.
502
Part IV Exchange Server
ExchangeSoapClient Class The ExchangeSoapClient class is shown in Listing 20-5. This class uses cURL to send SOAP requests over HTTPS with NTLM authentication. The following information is important to understand how this class works: ■
The constructor is overwritten to cache the passed options ($options).
■
The actual work is done by the doRequest() method.
■
Because the connection over HTTPS with NTLM authentication is time-consuming and resource-intensive, the open connection is cached in $this->curl_handle.
■
While the first connection is created, the (fixed) parameters are set. This includes not only the user name and password but also the CA root certificate (see the section “Query with cURL,” earlier in the chapter) as well as the returned response header (CURLINFO_HEADER_OUT) used for the tests.
■
Afterward, the (variable) parameters are set: SOAPAction header, URL of the service ($location), and SOAP message content ($request).
■
The metadata is retrieved by using curl_getinfo() and is available in the public $this>curl_info property for troubleshooting.
■
Because the response HTTP header is provided in $response, the XML SOAP message is separated from the HTTP headers.
The getLastRequestHeaders() and getLastResponseHeaders() methods are overwritten to return the correct values. Both functions should only be called if the trace option for the ExchangeSoapClient object is set. Listing 20-5 ExchangeSoapClient—the SoapClient class including HTTPS and NTLM-authentication.
503
504
Part IV Exchange Server
Using the ExchangeSoapClient Class Listing 20-6 shows how you use the ExchangeSoapClient class. It is important to set the CACert options, the logon name, and the password during the client instantiation. The trace option is necessary only for development tasks. After the instantiation has completed successfully, the GetFolder operation is called. The generated SOAP message (Listing 20-7) is defined by the $param array. Instead of using arrays, you can also define classes with appropriate properties and pass instantiated objects of these classes. If an error occurs, an exception is triggered that is intercepted in the try/catch block. For testing purposes, the request and the response, including the HTTP header as well as the response objects, are displayed. Listing 20-6 test-ews.php—testing the EWS with PHP.
Chapter 20 Exchange Web Services
505
The output of the test program is shown in Figure 20-1.
Figure 20-1 Output generated by the test program test-ews.php.
Listing 20-7 shows the generated SOAP request. The relationship between the $param array in Listing 20-6 and the SOAP message is obvious. Note The names specified in the $param array must be identical to the element and attribute names in the SOAP message (the names are also case sensitive).
Listing 20-7 A SOAP request from the GetFolder operation. Default
506
Part IV Exchange Server
Information About the Following Chapters In the following chapters, the SOAP messages are not given in full, and the PHP listings mostly show only relevant sections of the request.
Shorter SOAP Messages The following chapters don’t show full SOAP messages and use the namespace definition in Listing 20-8. Listing 20-8 Used XML namespaces. xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages"
The request in Listing 20-7 would look like this: Default
Shorter PHP Listings The PHP examples are also not listed in their entirety either and show only the structure of the request and the response. In addition, error-handling has been omitted. The PHP test program in Listing 20-6 would look like this: $param = array('FolderShape' => array('BaseShape' => 'Default'), 'FolderIds' => array( 'DistinguishedFolderId' => array(array('Id' => 'inbox'), array('Id' => 'drafts')))); $response = $client->GetFolder($param);
Chapter 20 Exchange Web Services
507
Object-Oriented Alternative for Parameters The SOAPClient class not only accepts parameters as arrays, but also as nested objects. Thus, an object-oriented alternative for Listing 20-6 would look like Listing 20-9. Using two simple classes and the default class, the listing shows how parameters are passed. Listing 20-9 Objects as parameters for SOAP operations. class FolderShape { protected $BaseShape; function __construct($shape) { $this->BaseShape = $shape; } } class FolderId { protected $Id; function __construct($id) { $this->Id = $id; } } $param = new \stdClass; $param->FolderShape = new FolderShape('AllProperties'); $param->FolderIds = new \stdClass; $param->FolderIds->DistinguishedFolderId = array(new FolderId('inbox'), new FolderId('drafts')); $response = $client->GetFolder($param);
With one exception (which is explained in Chapter 21, “Email and Exchange Web Services Basics”), you can choose any method: sometimes you need to use objects instead of arrays for EWS to work with PHP. Note This book primarily uses the array syntax.
508
Part IV Exchange Server
Summary This chapter explained how to use Autodiscover to retrieve the EWS URL. If the URL for the selected user is known, you can create the connection by using EWS and control it via Exchange. For PHP to work with EWS, you need to download the WSDL definition and the schemas and modify the WSDL file locally. As shown in the next chapter, you have to make more changes on the types.xsd XML schema. However, controlling the EWS based on WSDL simplifies programming with PHP significantly. The following chapter explains several terms of EWS and how to search, create, and delete emails in Exchange. The following chapters introduce additional aspects of the EWS, based on contacts and calendar entries.
Chapter 21
Email and Exchange Web Services Basics In this chapter: Structure, IDs, and Views . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Finding Folders (FindFolder) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Listing Messages (FindItem) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Viewing a Message (GetItem) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Requesting the Original MIME Content . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Sending a Message (CreateItem) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Deleting Messages (DeleteItem) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
509 513 516 522 524 531 536 538
This chapter explains important Microsoft Exchange Web Services (EWS) operations to find folders and elements and to create and delete elements. First, you will take a closer look at the Exchange database structure and the identification of elements. In addition to EWS operations, important EWS schema changes are also explained to ensure a trouble-free communication between EWS and PHP.
Structure, IDs, and Views Exchange saves all elements in an internal database. This database isn’t a relational database with tables and typed columns; rather, it’s a generic storage for organized data. For each element, the element data, the element type, a unique ID, and version information are saved in the Exchange database. Because the version information changes if an element is modified, Exchange can ensure that only current data is updated, if accessed simultaneously. Except for search functions, elements are accessed through their ID. At the same time a change key, aptly named ChangeKey, is passed containing the version and type information of the element. Although ChangeKey is optional, it should be specified to recognize simultaneous changes.
509
510
Part IV Exchange Server
IDs of Labeled Folders Several labeled folders have well known aliases. Table 21-1 lists several folder aliases. However, if possible, you should use the real ID of a folder instead of its alias. Table 21-1 IDs for labeled folders
Name
ID
Description
Drafts
drafts
New messages the user hasn’t sent yet; used for caching.
Deleted Items
deleteditems
Deleted messages not removed yet (recycle bin).
Sent Items
sentitems
Sent messages.
Junk E-mail
junkemail
Unwanted messages.
Calendar
calendar
Default folder for calendar entries.
Contacts
contacts
Default folder for contacts.
Message root folder
msgfolderroot
The root folder for all message folders.
Outbox
outbox
Messages are saved in this folder until they are sent.
Inbox
inbox
New messages are saved in this folder.
Root folder
root
The top folder in the Exchange mailbox.
Use DistinguishedFolderId to specify the alias IDs for operations to distinguish these IDs from the real IDs, which are specified in FolderId.
Viewing Elements Elements in the Exchange database consist of properties with names and values. Properties are typed. This means syntax and limitations for values are defined. For search results (for example, FindFolder) or queried elements (GetItem), you can use BaseShape to specify which properties are included in the results. BaseShape defines profiles for frequent use cases: Default for the standard properties, IdOnly if only the ID of an element is needed, and AllProperties to include all properties of an element in the results. If you want a view to include additional properties, specify these properties with AdditionalProperties. Caution A query returns only the first 256 characters (for Unicode, otherwise 512 characters) of strings and other large data types. Only a direct query, such as with GetItem, returns all information.
Calculated properties (properties that are dynamically generated and not saved in the database) cannot be returned as part of search queries.
Chapter 21 Email and Exchange Web Services Basics
511
Selected Properties of Elements Table 21-2 lists selected properties of elements together with a short description. Table 21-2 Selected standard properties of elements
Property
Description
Attachments
Lists all attachments of an element
Body
Text of the element
Categories
Categories assigned to the element
DateTimeCreated
Specifies when the element was created
DateTimeReceived
Specifies when the element arrived in the mailbox
DateTimeSent
Specifies when the element was sent
HasAttachments
Specifies if the element has attachments
ItemClass
Element type of email messages such as IPM.Note
ItemId
ID and version (ChangeKey) of the element
LastModifiedName
Display name of the user who changed the element last (read-only)
LastModifiedTime
Time the element was last changed (read-only)
ParentFolderId
Folder in which the element is saved
ReminderDueBy
Time of the reminder, due date
ReminderIsSet
Specifies if the reminder function is enabled
ReminderMinutesBeforeStart
Specifies the number of minutes before the due date for the reminder
Size
Size of the element in bytes
Subject
Subject of the element
Names of Properties For some operations or parameters of operations, you must specify the property names these properties have in the Exchange database (not the position or the element names in XML of the SOAP message—although the XML element name of the property is often very similar to the name in the database). This might be necessary if you want to sort the search results by properties or to return additional properties with AdditionalProperties. Exchange differentiates between three property types: basic properties, property groups, and extended properties.
512
Part IV Exchange Server
Basic Properties Basic properties are properties that are only set once per element but can have several values. The display name of folders (folder:DisplayName) or categories for elements (item:Categories) are examples of basic properties.
In requests, basic properties are specified by using FieldURI:
For a list of the basic properties, consult the MSDN article at http://msdn.microsoft.com/ en-us/library/aa494315.aspx. A complete list can be found in the types.xsd XML Schema of the EWS in the definition of the UnindexedFieldURIType data type.
Property Groups Property groups consist of properties that can be included in an element multiple times. Typical examples are phone numbers for contacts (contacts:PhoneNumber) or contact information (contacts:ImAddress).
In requests, the entries of property groups are specified by using IndexedFieldURI:
For a list of property groups, consult the MSDN article at http://msdn.microsoft.com/en-us/ library/aa581079.aspx. A complete list can be found in the types.xsd XML Schema of the EWS in the definition of the DictionaryURIType data type.
Extended Properties You can use extended properties (ExtendedFieldURI element) to specify additional MAPI properties. These properties are addressed by their types and either the predefined names, their tags, or the IDs.
For a description of the syntax and the predefined names, consult the MSDN article at http:// msdn.microsoft.com/en-us/library/aa564843.aspx.
Chapter 21 Email and Exchange Web Services Basics
513
Finding Folders (FindFolder) For the EWS to work with email, you first need to find the folders in which the emails are saved. This is done by using the FindFolder operation.
Selected Properties Folders are the only objects in the Exchange database that are not derived from the generic element type. Therefore, folders have their own set of properties. The most important properties are listed in Table 21-3. Table 21-3 Selected properties of folders
Property
Description
ChildFolderCount
Number of folders in the folder
DisplayName
Display name of the folder
FolderClass
Class of the folder such as IPF.Note for the inbox
FolderId
ID and version (ChangeKey) of the folder
ParentFolderId
ID of the parent folder
TotalCount
Number of elements in the folder
Request Listing 21-1 shows an example request that uses the FindFolder operation. Listing 21-1 The FindFolder operation—request message. AllProperties
In PHP, the ExchangeSoapClient class generates the operation message as follows: $param = array('Traversal' => 'Deep', 'FolderShape' => array('BaseShape' => 'AllProperties'), 'ParentFolderIds' => array( 'DistinguishedFolderId' => array('Id' => 'msgfolderroot'))); $response = $client->FindFolder($param);
514
Part IV Exchange Server
The following parameters are passed to FindFolder: ■
Traversal Specifies the search area. Deep searches the entire hierarchy below the specified folder, and Shallow searches only the direct children.
■
ParentFolderIds Contains one or more folder IDs to be queried. DistinguishedFolderId specifies alias IDs, and FolderId specifies IDs. For example:
Response The response from the FindFolder operation contains the data of the folders that were found. The PHP SOAP extension converts the structure of the SOAP message into a PHP object.
XML Response Listing 21-2 shows the response from the operation. In addition to the status information (ResponseClass, ResponseCode), the number of hits is also indicated (TotalItemsInView). It also shows if the last element is included in the results (IncludesLastItemInRange). The last information is useful if search results are paginated. Folders contains the actual folder information. Listing 21-2 The FindFolder operation—response message. NoError IPF.Note Inbox 17 2 0 ...
Chapter 21 Email and Exchange Web Services Basics
515
PHP Object The PHP SOAP extension converts the response XML to a PHP object. Nested elements correspond to nested objects. Listing 21-3 shows how the elements are handled: $folderlist shows the message structure, and the folder array (Folder elements) is processed in a loop. Notice that with $folder-> ParentFolderId->Id, XML elements and attributes are addressed in the same way. Note Listing 21-3 uses HTMLPage.php (see Appendix A, “Example Scripts and Data”) to display the data as a table.
Listing 21-3 Evaluating the response message from the FindFolder operation. $page = new HTMLPage('Folders in Mailbox'); $folderlist = $response->ResponseMessages->FindFolderResponseMessage ->RootFolder->Folders->Folder; $folders = array(); foreach ($folderlist as $folder) { $folders[$folder->FolderId->Id] = $folder; } $table = array( array('Name', 'Folder Class', 'Parent Folder', 'Elements', 'Unread') ); foreach ($folders as $folder) { $parentId = $folder->ParentFolderId->Id; $parent = isset($folders[$parentId]) ? $folders[$parentId]->DisplayName : 'msgfolderroot'; $table[] = array($folder->DisplayName, $folder->FolderClass, $parent, $folder->TotalCount, $folder->UnreadCount); } $page->addTable($table); $page->printPage();
Figure 21-1 shows the output from the sample program.
516
Part IV Exchange Server
Figure 21-1 All folders in the mailbox.
Listing Messages (FindItem) The FindItem operation lists the email messages. This operation works similar to FindFolder. Because folders can contain a large number of emails, you might want to limit the search results.
Limiting the Results (Paging) With the EWS IndexedPageItemView element, you can limit the number of the search results returned by the FindItem operation:
MaxEntriesReturned specifies how many hits are returned, Offset specifies the start position, and Basepoint specifies whether the offset count starts at the first element in descending order or at the last element in ascending order to simplify scrolling in both directions. Note Instead of IndexedPageItemView, you can use FractionalPageItemView to specify a relative (percentage) offset (numerator and denominator attributes).
Chapter 21 Email and Exchange Web Services Basics
517
In this case, the RootFolder element of the response contains the following attributes:
IndexedPagingOffset contains the offset value used for the next request. This value is calculated from Offset+MaxEntriesReturned. TotalItemsInView indicates how many elements are saved in the folder, and IncludesLastItemInRange specifies if the search result contains the last element: if IncludesLastItemInRange=true and the order is descending (BasePoint=Beginning), it is the last element in the folder. If the order is ascending (BasePoint=End), the first element in the folder is included in the search results. Note You can also limit the number of results for the FindFolder operation by using the IndexedPageFolderView and FractionalPageFolderView elements.
Sorting Use the SortOrder element presented in Listing 21-4 to sort the search results returned by FindItem. The properties are displayed in the specified order. Listing 21-4 Specifying the sort order.
Exchange returns the results in the specified order. In this example, the order is ascending beginning at the sender (message:Sender) and descending beginning at the time sent (item:DateTimeSent), if the sender is the same. Note You cannot sort the results from the FindFolder operation.
PHP and Replacement Groups The PHP SOAP extension cannot generate the correct XML in Listing 21-4 because in the EWS schema definition, the FieldURI, IndexedFieldURI, and ExtendedFieldURI elements are
518
Part IV Exchange Server
defined as a replacement group for the path element. Therefore, PHP returns an error message stating that the path element is missing. There are two solutions: you can modify the EWS schema definition to not use replacement groups, or you can use type mapping to perform the XML serialization in the SoapClient.
Type Mapping Type mapping cannot be used because of an error in EWS. EWS cannot process schema instances with xsi:type; it returns an internal server error. If you still want to use type mapping, you need to map all parent types. This is possible, but for all practical purposes, it’s too much effort. Therefore, this book doesn’t use type mapping; instead, it modifies the
schema.
Modifying the Schema To break the deadlock between PHP and EWS and to take advantage of the programming functionality based on WSDL, you need to modify the schema for the web services. To do this, perform the following steps:
1. Open the local copy of the types.xsd type schema in an editor.
2. Insert the following lines into the schema (at the end, before the xs:schema end tag):
3. Replace all instances with .
4. Change the definition of NonEmptyArrayOfPathsToElementType as follows:
Note You need to handle this type in a special way because PHP (currently) ignores the information relating to groups from maxOccurs.
Chapter 21 Email and Exchange Web Services Basics
519
5. Save the schema file.
Based on these modifications, PHP generates the correct XML for the SOAP message.
Request After all preparations are completed, you can easily create a request that limits the results to five elements and sorts these elements by sender name and creation date.
XML Request The XML request from the FindItem operation is shown in Listing 21-5. The results are limited by using MaxEntriesReturned and the offset and order are specified by using BasePoint. Use SortOrder to specify the sort order and ParentFolderIds to specify the folders to be searched. Listing 21-5 Message search with result limit and sorting. Default
PHP Due to the modified EWS type schema, PHP creates the request as if it would be able to handle replacement groups. This is shown in Listing 21-6.
520
Part IV Exchange Server Listing 21-6 Creating and starting the FindItem operation. $param = array('Traversal' => 'Shallow', 'ItemShape' => array('BaseShape' => 'Default'), 'ParentFolderIds' => array( 'DistinguishedFolderId' => array('Id'=>'inbox')), 'IndexedPageItemView' => array( 'MaxEntriesReturned'=> 5, 'Offset' => 0, 'BasePoint' => "Beginning"), 'SortOrder' => array( 'FieldOrder' => array( array('Order' => 'Ascending', 'FieldURI' => array('FieldURI' => 'message:Sender')), array('Order' => 'Descending', 'FieldURI' => array('FieldURI' => 'item:DateTimeCreated')) ))); $response = $client->FindItem($param);
The example listing specifies an alias ID (inbox) without ChangeKey for the parent folder. In production environments, you should always specify the ChangeKey.
Response The response message contains the searched email messages with the properties specified in the default view.
XML Response Listing 21-7 shows the response message from the operation. The email messages found are embedded as message elements in the response, and due to the requested Default-Item Shape, they contain the most important properties for the listing. In this view, the sender data (from) doesn’t include the email address but only the sender name. The content of the email (Body) is also not included.
Chapter 21 Email and Exchange Web Services Basics Listing 21-7 The FindItem operation—response message. NoError Furious Furrows...ResponseMessages->FindItemResponseMessage ->RootFolder->Items->Message; $table = array( array('Sender', 'Subject', 'Date', 'Read', 'Size', 'Attachments') ); foreach ($messages as $msg) { $read = $msg->IsRead ? 'yes' : '-'; $attachments = $msg->HasAttachments ? 'yes' : '-'; $table[] = array($msg->From->Mailbox->Name, $msg->Subject, $msg->DateTimeSent, $read, $msg->Size, $attachments); } $page->addTable($table); $page->PrintPage();
521
522
Part IV Exchange Server
The output of the program is displayed in Figure 21-2. With the Id and ChangeKey values, a complete web mail script would include additional links to the detailed view of the emails. Important Direct access to Items->Message (Listing 21-8) only displays email messages and no appointments or other messages because these have the MeetingRequest or MeetingCancellation type. To list all elements, you must iterate through the results twice. $items = $response->ResponseMessages->FindItemResponseMessage->RootFolder->Items; foreach ($items as $itemType) { foreach ($itemType as $singleItem) { ... } }
Remember that other message types have properties different from email messages and, therefore, must be handled in a different way.
Figure 21-2 The message elements in the inbox.
Viewing a Message (GetItem) To retrieve a single message, use GetItem. Unlike FindItem, GetItem has no 256/512 character limit for properties; it returns the full values of properties. Email attachments that must be transferred separately and the original MIME email data are excluded. Because emails can contain HTML content, there is a risk if this content is not filtered and displayed as-is in the browser. An email can contain scripts or other dangerous HTML content. To this end, Exchange Server 2010 provides an HTML filter. However, Exchange Server 2010 mode must be requested within a SOAP header.
Chapter 21 Email and Exchange Web Services Basics
523
Requesting the Exchange 2010 Mode Within a SOAP Header If you need the current version of Exchange Server to use new functions, you need to insert the version into the request as a SOAP header. Listing 21-9 shows the full SOAP request message: whereas the GetItem operation is included in the SOAP body, RequestServerVersion is transferred as a SOAP header. Listing 21-9 SOAP header RequestServerVersion to perform the operation in Exchange Server 2010 mode. ...
In PHP, the header is generated with the SoapHeader class and set with __setSoapHeaders() (see Listing 21-10). Note that depending on your version of Exchange Server, the version string might be slightly different. To set multiple headers, the headers are passed as an array to __setSoapHeaders(). If NULL is passed, all headers are deleted. Listing 21-10 The PHP code to create the SOAP header. $client = new ExchangeSoapClient("./Services.wsdl", $options); $version = array('Version' => "Exchange2010_SP1"); $header = new \SoapHeader(ExchangeSoapClient::TYPES_NS, 'RequestServerVersion', $version); $client->__setSoapHeaders($header);
Important The IDs in Exchange 2010 are different from the those in Exchange 2007. If you want to access an element at a later time, you need to use the Exchange 2010 mode for the previous FindItem operation. Because the ExchangeSoapClient class used in this book allows recycling, the header needs to be set only once after the instantiation.
524
Part IV Exchange Server
Defining and Filtering the Message Content Email messages contain text or HTML content. If you want to query the content, use the BodyType element to specify which format should be returned, as shown in the following: Default HTML
There are three possible values for BodyType: HTML, Text, and Best (which is the default, delivers HTML if available; otherwise, plain text). If the content has the wrong format, Exchange converts the content automatically into the desired format. Because HTML messages can contain active content that might compromise security, these contents should be filtered before opened in a browser. However, it is very difficult to write a reliable HTML filter yourself. Fortunately, Exchange 2010 has a built-in HTML filter that you can specify in the ItemShape element: Default true
Valid values for FilterHtmlContent are true and false. For this function, the request has to force the processing in Exchange 2010 mode (SOAP header RequestServerVersion).
Requesting the Original MIME Content The content returned in the body property is already decoded and might already be transformed or filtered. To obtain the original MIME message, specify the IncludeMimeContent element: Default true
Valid values for IncludeMimeContent are true and false. The returned MIME message is Base-64 encoded and must be decoded for further processing. The MIME message is complete; the message contains the SMTP header, the message content, and possibly attachments.
Chapter 21 Email and Exchange Web Services Basics
525
Note Because email attachments can be large, you should consider the PHP memory require-
ments. Keep in mind that you might need three to four times the storage space of the email size for processing.
Request Using the techniques from the preceding sections, you can easily create the request. Listing 21-11 shows how to retrieve two elements in a single operation. Listing 21-11 The GetItem operation—request message. Default HTML true
The request created by using PHP has the usual pattern, as demonstrated in Listing 21-12. In the listing, $item1 and $item2 are result objects from a previous FindItem operation. Listing 21-12 The GetItem operation in PHP. $param = array('ItemShape' => array('BaseShape' => 'Default', 'BodyType' => 'HTML', 'FilterHtmlContent' => true), 'ItemIds' => array('ItemId' => array( array('Id' => $item1->ItemId->Id, 'ChangeKey' => $item1-> ItemId->ChangeKey), array('Id' => $item2->ItemId->Id, 'ChangeKey' => $item2-> ItemId->ChangeKey))) ); $response = $client->GetItem($param);
526
Part IV Exchange Server
Response Listing 21-13 shows the response message from the GetItem operation in Listing 21-11. Both responses for the queried elements are saved in their own GetItemResponseMessage elements instead of within items for FindItem. This way, you can map errors (ResponseClass, ResponseCode) at the element level. The HTML content (Body) in the XML message is entity-encoded so that the HTML doesn’t impact the validity of the XML message. However, the HTML in the corresponding PHP object ($response) is available in clear text. Keep in mind that the HTML comprises , , and elements, not just the content of the HTML element itself. Listing 21-13 Response message from the GetItem operation. NoError Fun at de Efteling Normal
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
HTML Content
Email with HTML content.
53200 2011-02-10T10:57:26Z 2011-04-19T15:46:17Z false false Tony H. Hamster
[email protected] SMTP Mailbox
Chapter 21 Email and Exchange Web Services Basics
527
... false ... false ...
The sender (From) and the recipient (ToRecipients, CcRecipients) are indicated by name and email address in GetItem in the Mailbox element. The MailboxType element provides more information about the address. For example, the Mailbox value indicates an Exchange mailbox. Note For a list and description of all values for MailboxType, consult the MSDN article at http://msdn.microsoft.com/en-us/library/aa563493.aspx.
Example Listing 21-14 shows a full example how an email message is retrieved and displayed by using EWS. The script is created as follows: ■
First, an ExchangeSoapClient is instantiated, and a SOAP header for Exchange 2010 is set to use the FilterHtmlContent function.
■
The message to be displayed is specified with the id and changekey GET parameters. Important Because the request uses the Exchange 2010 mode, the previous FindItem operation must also be performed in Exchange 2010 mode. Otherwise, id and changekey don’t match.
■
The $param array is created and the GetItem operation is called.
■
Afterward, certain fields of the email are written in a table (the necessary auxiliary functions are to be found at the end of the script).
This example doesn’t check or solve errors, and the output of the ToRecipients field is simplified: the email could have several recipients.
528
Part IV Exchange Server Listing 21-14 show-msg.php—retrieving and viewing an email.
Chapter 21 Email and Exchange Web Services Basics
529
Figure 21-3 shows the output of a message using the script in Listing 21-14. The HTML content was already filtered by Exchange.
Figure 21-3 Output generated by the sample script msg.php.
Email Attachments (GetAttachment) If an email has one or more attachments, GetItemResponseMessage includes the information shown in Listing 21-15, which includes file name, size and type of the attachment, and the Exchange ID of the attachment for further processing. Listing 21-15 Information about the attachments in the GetItem response message. NoError ... CurrentPriceList.xls application/vnd.ms-excel dfeef8b3-e589-4c86-b463-10751e9b0906 24816 2011-08-19T15:46:17 false false
530
Part IV Exchange Server
... ... true ...
The GetAttachment operation is used to retrieve email attachments.
Request Creating a request for the GetAttachment operation is straightforward:
You can specify multiple AttachmentId in one request. You can also use AttachmentShape (such as FolderShape and ItemShape) to specify properties; the IncludeMimeContent, BodyType, FilterHtmlContent, and AdditionalProperties elements are available. The PHP code to retrieve an attachment is also short, and there is no ChangeKey: $param = array('AttachmentIds' => array( 'AttachmentId' => array('Id' => "AQMkADhh..."))); $response = $client->GetAttachment($param);
Response Listing 21-16 shows the response. The content is essentially the same as the results returned by the GetItem operation. The only difference is that the content in the content element is Base-64 encoded. The content in the PHP $response object is already decoded. Listing 21-16 The GetAttachment operation—response message. NoError
Chapter 21 Email and Exchange Web Services Basics
531
GeneralInformation.pdf application/octet-stream dfeef8b3-e589-4c86-b463-10751e9b0906 ...
In PHP, you can access the content as follows: $response->ResponseMessages->GetAttachmentResponseMessage->Attachments ->FileAttachment->Content
If several attachments were requested in a single GetAttachment operation, you access the content as follows: foreach ($response->ResponseMessages->GetAttachmentResponseMessage as $msg) { $content = $msg->Attachments->FileAttachment->Content; ... }
Sending a Message (CreateItem) An email is sent if the CreateItem method creates a message element and Exchange is instructed to send this element. Exchange determines the recipient from the element and delivers the message accordingly. If you send messages (or perform other EWS operations), EWS might not recognize the XML of the SOAP request generated by PHP because the content of the request is redundant. To avoid this problem, you need to use cloned objects instead of the array structure for parameters.
SOAP Errors Caused by References and Accessors If a message or other elements are created, the request message might contain certain data multiple times. SOAP provides a method to reduce the size of the request: accessors (MRA, multi-reference accessor) reference data at another position. Listing 21-17 shows an example in an email message. In the listing, the sender adds herself to the CcRecipients element.
532
Part IV Exchange Server Listing 21-17 The sender and Cc recipient are identical. Doris D. Lass
[email protected] Doris D. Lass
[email protected]
With the MRA method, the duplicated structure isn’t necessary (see Listing 21-18). An id attribute is added to the first record, which is referenced by the second record by using href. Listing 21-18 Reference and accessor (MRA) reduce the size of messages. Doris D. Lass
[email protected]
Problem PHP creates the request XML according to the described method. However, Exchange 2010 doesn’t support the MRA method; instead, it returns an error (XML doesn’t match schema). How can you write the PHP to create the XML in Listing 21-17?
Solution If the operation parameters are created as objects instead of arrays in PHP and no object is used twice, PHP creates the version from Listing 21-17. Listing 21-19 shows how the solution could look. In the listing, the mailbox class is instantiated once, and for the operation parameters, the object is cloned.
Chapter 21 Email and Exchange Web Services Basics
533
Listing 21-19 Avoiding the cloning of references and accessors. class Mailbox { protected $EmailAddress; protected $Name; function __construct($address, $name=NULL) { $this->EmailAddress = $address; $this->Name = $name; } } $doris = new Mailbox('
[email protected]', 'Doris D. Lass'); $param->Sender->Mailbox = $doris; $param->CcRecipients->Mailbox = clone $doris;
Request To send an email, create the email by using CreateItem, and then send it. You can also save the email in the Drafts folder (or in another folder).
XML Request Listing 21-20 shows the typical properties used for this operation, which are described in the following: ■
ItemClass Email messages have the IPM.Note class
■
Subject Subject of the message
■
Body Message content
■
Sender Sender of the message
■
ToRecipients, CcRecipients Recipients of the message
Listing 21-20 The CreateItem operation—request message to send an email. IPM.Note AdventureWorks: Support ticket #45260 Bicycle headlight is broken. Tony H. Hamster
[email protected]
534
Part IV Exchange Server
[email protected] Tony H. Hamster
[email protected]
The MessageDisposition attribute determines if the email is sent or only saved. This attribute can have the following values: ■
SaveOnly The email is only saved (to the default folder: Drafts).
■
SendOnly The email is only sent and no local copy is saved.
■
SendAndSaveCopy The email is sent and saved (by default in the Sent Items folder).
Note If you want to send a saved email at a later time, use the SendItem operation. You can also use SendItem to resend already sent emails. If you don’t want to save the email in the default folder, use SavedItemFolderId to specify a different folder: ...
You can create and send several emails in a single CreateItem call. In this case, an email is saved with its own message structure within items. Therefore, ensure that the MRA method of PHP is not enabled (see the section “SOAP Errors Caused by References and Accessors,” earlier in the chapter).
Chapter 21 Email and Exchange Web Services Basics
535
Creating an Email by Using PHP Listing 21-21 shows how to use PHP to create and send an email. To do this, you use the Mailbox class in Listing 21-19. Instead of the array syntax, the operation parameters consist only of objects (for the request to work you need to pass $tony as two separate objects). Listing 21-21 Creating and sending an email by using CreateItem.
Figure 21-4 shows the email created and sent in the Outlook Web App of Exchange 2010. The message content is plain text. To send the message as HTML the Body->BodyType in Listing 21-21 needs to be set to HTML and the content must be formatted as HTML.
536
Part IV Exchange Server
Figure 21-4 An email created in Outlook Web App.
Response The response message is short and precise: the response indicates if the operation was successful or failed, but it doesn’t contain any further information (see Listing 21-22). Listing 21-22 The CreateItem operation—response message. NoError
Deleting Messages (DeleteItem) You can delete messages and other elements by using the DeleteItem operation. The IDs of the elements to be deleted as well as the parameter DeleteType that specifies which method is used are passed to the operation. Use MoveToDeletedItems to move the element to be deleted into the Deleted Items folder; use HardDelete to permanently delete the element. Use SoftDelete to keep the element in the folder, but mark it as deleted.
Chapter 21 Email and Exchange Web Services Basics
537
XML Messages Listing 21-23 shows how the XML message for the request looks. The listing deletes two elements in two separate ItemId elements. Listing 21-23 The DeleteItem operation—XML message of the request.
Listing 21-24 shows the response message. For each deleted element, a separate DeleteItem ResponseMessage is returned. Listing 21-24 Response message from the DeleteItem operation. NoError NoError
PHP Listing 21-25 shows the DeleteItem operation call in PHP. Listing 21-25 Deleting elements by using PHP. $param = array('DeleteType' => 'MoveToDeletedItems', 'ItemIds' => array( 'ItemId' => array( array('Id' => $itemId1, 'ChangeKey' => $changeKey1), array('Id' => $itemId2, 'ChangeKey' => $changeKey2)))); $response = $client->DeleteItem($param);
The DeleteItem operation uses two additional parameters (SendMeetingCancellations, Affected TaskOccurrences), which you can set to delete meetings or tasks. However, meetings should be deleted with a meeting cancellation (CancelCalendarItem).
538
Part IV Exchange Server
Summary EWS operations provide access to the Exchange data. Use FindFolder, FindItem, and GetItem to query and to view folders and elements and CreateItem to create new elements and DeleteItem to delete elements. Other operations for elements are UpdateItem, MoveItem, and CopyItem. UpdateItem is introduced in the next chapter. Elements in the Exchange database consist of properties and have an ID (Id) and a version (ChangeKey) to identify the element for operations. You indicate the properties displayed for operations by using views (FolderShape, ItemShape). Programming EWS with PHP is basically straightforward, but because of flaws in the PHP SOAP extension and the incompatibility between EWS and PHP, the EWS schema must be modified. The following chapter introduces contacts and explains how search expressions are used to query elements with certain properties.
Chapter 22
Contacts and Search In this chapter: Properties of Contacts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Changing a Contact (UpdateItem) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Finding Certain Properties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Defining the Search in a Request . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
539 543 548 552 558
Microsoft Exchange provides functions to save and manage contacts. Contact elements are handled in the same manner as email messages. The FindItem, GetItem, CreateItem, UpdateItem, DeleteItem, CopyItem, and MoveItem operations are used in the same way for contacts. The following sections describe the properties of contact elements in detail. The UpdateItem operation (which has not been described yet) is used as an example to explain how values in property groups are handled. Afterward, you will learn how to use the FindItem operation to query elements with certain properties. The Restriction element passed as a parameter can be used to search for emails, calendar entries, or tasks.
Properties of Contacts Contacts are elements in the Exchange database that are saved in a contact folder. These elements have the IPM.Contact type and are represented in SOAP messages by the Contact element. The DistinguishedFolderId for the default contact folder is contacts. Exchange can access contacts in Microsoft Active Directory, but using Exchange Web Services (EWS), applications just have read-only access.
Standard Properties Table 22-1 lists frequently used standard properties of a contact element. Contacts inherit the almost 40 properties of the basic element type, including: ItemId, ItemClass, Categories, DateTimeCreated, and Subject.
539
540
Part IV Exchange Server
For a contact, ItemClass has the value IPM.Contact. The Subject (from the basic element type) and DisplayName (from the contact type) properties have the same meaning, but most of the time, programs use only one of the two properties. To ensure contacts are displayed correctly in all programs, you should always use Subject and DisplayName. Table 22-1 Selected properties of a contact
Property
Type
Description
Birthday
dateTime
Date of birth
BusinessHomePage
anyURI
Company website
CompanyName
string
Company
CompleteName
Name structure
See Table 22-2 (read-only)
ContactSource
enumeration
Exchange database (Store) or Active Directory (ActiveDirectory)
DisplayName
string
Name displayed
EmailAddresses
Sequence of email addresses
See Table 22-3
FileAs
string
Name for the sort or display order (Save as in Outlook)
FileAsMapping
enumeration
Method to automatically generate FileAs, for example, LastCommaFirst
GivenName
string
First name
ImAddresses
Sequence of addresses
Instant messaging addresses
Initials
string
Initials (first letters of middle names)
JobTitle
string
Position within the company
MiddleName
string
Middle name
PhoneNumbers
Sequence of numbers
Phone numbers
PhysicalAddresses
Sequence of addresses
See Table 22-4
Surname
string
Last name
Listing 22-1 shows the XML structure for a contact, including a group property (phone numbers). Listing 22-1 XML example for a contact. IPM.Contact Doris D. Lass LastCommaFirst Doris D. Lass Doris
Chapter 22 Contacts and Search
541
D. Doze and Sleep +12 (345) 6789-0 +98 (765) 43210 Department Manager Lass
Note For a complete list of the properties for a contact element, consult the MSDN article at http://msdn.microsoft.com/en-us/library/aa581315.aspx.
Name Properties The name properties of a contact reside in the standard properties and in the CompleteName property. CompleteName is read-only and the values are filled in from the standard properties. Table 22-2 shows these properties and their relationship with the standard contact properties. If a contact is retrieved by using the Default ItemShape profile, only the CompleteName properties are returned but not the associated name properties of the contact. Table 22-2 Selected properties of CompleteNameType and their mapping to contact properties
Property
Contact property
Description
FirstName
GivenName
First name
FullName
DisplayName
Display name, full name in a property
Initials
Initials
Initials (first letters of the middle names)
LastName
Surname
Last name, surname
MiddleName
MiddleName
Middle name
Nickname
Nickname
Nickname
Suffix
Generation
Name affix, such as Jr. or Sr.
Title
MAPI tag 0x3A45
Salutation/title
542
Part IV Exchange Server
Listing 22-2 shows an example of the XML structure for the CompleteName property. Listing 22-2 XML example for a name structure. Doris D. Lass Doris D. Lass
Properties of Email Addresses Email addresses are a property group that can contain three saved addresses. Table 22-3 lists these properties. Table 22-3 Properties of the data type email address
Property
Type
Description
_
string
Email address (content of the element “_” in PHP)
Key
enumeration
Valid values are EmailAddress1, EmailAddress2, EmailAddress3
MailboxType
enumeration
Type of the mailbox, such as a Mailbox or OneOff
Name
string
Name of the email account
RoutingType
string
Should always have the value SMTP
Listing 22-3 shows an example. In the listing, the email address is included in the element content, and the other properties are attributes. Listing 22-3 XML example of the email address structure.
[email protected] [email protected]
Chapter 22 Contacts and Search
543
Address Properties You can save three different addresses for a contact: the business address (Business), the home address (Home), and an additional address (Other). Use the PostalAddressIndex contact property to indicate which of the three addresses is used as the postal address. Table 22-4 lists the properties of an address entry. Table 22-4 Properties
of addresses
Property
Type
Description
City
string
City
CountryOrRegion
string
Country
Key
enumeration
Valid values are Business, Home, Other
PostalCode
string
Postal code
State
string
State
Street
string
Street, including street number and other details
Listing 22-4 shows how to specify the home address. Listing 22-4 XML example of an address. Dwarfs 7 Sevenmountainville Far Away Land 12345 Home
Changing a Contact (UpdateItem) To change the contact data, use the UpdateItem operation. UpdateItem offers three functions to change properties: ■
SetItemField Sets (and overwrites) the properties of an element.
■
DeleteItemField Deletes a property.
■
AppendToItemField Adds data to an existing property. This function is allowed only for certain properties. For example, for contacts, it’s allowed only for the note property represented by the body element.
544
Part IV Exchange Server
Request The UpdateItem operation can change several elements—and in each element, several properties—at the same time. Use ItemChange to specify elements and Updates for the properties that you want to change. The three change functions have the same format: the property to be changed is defined by an identifier, and the new or added data are indicated in the same structure as the elements. (You don’t have to specify this data if you delete a property.) The property that is changed is declared twice: once by its name, and then by the structure. However, EWS expects both declarations, which must correspond. Note A list of the property names can be found in the types.xsd XML schema (UnindexedField URIType and DictionaryURIType) and in the MSDN article at http://msdn.microsoft.com/en-us/ library/aa581022.aspx (click the link to the desired sub type).
The operation also expects information regarding conflicts if the ChangeKey is not current, as a result of a change that occurred in the meantime. There are three possible modes (through ConflictResolution): ■
NeverOverwrite If a conflict occurs, the process is terminated with an error.
■
AlwaysOverwrite The current change overwrites all previous changes.
■
AutoResolve Exchange tries to resolve the conflict. If the conflict can be solved, the change is applied. Otherwise, Exchange returns an error.
Which mode you use depends on your requirements. Because the functionality of AutoResolve is quite limited, it almost always behaves like NeverOverwrite.
XML Request Listing 22-5 shows the XML of an example request. The following changes are made to the properties: ■
The nickname is set to a new value. Note The nickname is not displayed in Outlook Web App.
Chapter 22 Contacts and Search
545
■
The state is set for the home address (property group). It is apparent that the property is set twice. The key is located in the FieldIndex and in the Key attribute.
■
Text is added to the note (body).
■
The Manager property is deleted.
Listing 22-5 UpdateItem operation—XML request to change a contact. Doribori Manymountains Expert in time travel.
546
Part IV Exchange Server
Creating the Request in PHP Listing 22-6 shows how the UpdateItem operation is created in PHP and the XML structure is reflected in the array nesting of $param. Listing 22-6 Creating and starting the UpdateItem operation in PHP. // $itemId contains the contact's ID information $param = array('ConflictResolution' => 'AutoResolve', 'ItemChanges' => array( 'ItemChange' => array( 'ItemId' => array('Id' => $itemId->Id, 'ChangeKey' => $itemId->ChangeKey), 'Updates' => array( 'SetItemField' => array( array( 'FieldURI' => array('FieldURI' => 'contacts:Nickname'), 'Contact' => array('Nickname' => 'Doribori')), array( 'IndexedFieldURI' => array( 'FieldURI' => 'contacts:PhysicalAddress:State', 'FieldIndex' => 'Home'), 'Contact' => array( 'PhysicalAddresses' => array( 'Entry' => array( 'Key' => 'Home', 'State' => 'Manymountains'))))), 'AppendToItemField' => array( 'FieldURI' => array('FieldURI' => 'item:Body'), 'Contact' => array( 'Body' => array('_' => "\nExpert in time travel.", 'BodyType' => 'Text'))), 'DeleteItemField' => array( 'FieldURI' => array('FieldURI' => 'contacts:Manager')) )))); $response = $client->UpdateItem($param);
Figure 22-1 shows the contact before and after the UpdateItem operation; in Outlook Web App in the figure, the field Manager is deleted, the State is new, and Note contains an additional row. Because AppendToItemField adds the new text directly, the line break has to be inserted with \n, as shown in Listing 22-6.
Chapter 22 Contacts and Search
547
Figure 22-1 Updating a contact entry (Contact view in Outlook Web App).
Response Listing 22-7 shows the response from the UpdateItem operation. For each element, the ItemId is returned with the new ChangeKey.
548
Part IV Exchange Server Listing 22-7 The UpdateItem operation—XML response message. NoError
Finding Certain Properties Until now, we used the FindItem operation only to find and list the content of folders. Chapter 21, “Email and Exchange Web Services Basics,” described paging and sorting search results. But if a folder (for example, the contact folder or the inbox) contains a large number of elements, it makes sense to only return elements that meet certain criteria. In Exchange, you can do this by using search limits (restriction parameter). Using search expressions, you can create complex queries to check if properties have certain values. Because replacement groups are used, you need to modify the XML schema for PHP to communicate with EWS.
Expressions EWS provides different search expressions for queries: ■
Boolean expressions to link other expressions
■
Comparison expressions to compare the property values with a given value or with other properties
■
Additional expressions to compare names or to check if a property exists
The combination of these expressions allows you to create almost any query. All expressions refer to the element being checked. Therefore, the combination with other elements in the query is not possible (for instance, a search similar to a JOIN in a relational database).
Chapter 22 Contacts and Search
549
Boolean Expressions Three Boolean expressions are implemented in EWS (see Table 22-5). Table 22-5 Boolean expressions
Expression
Description
And
Boolean AND operator to combine expressions
Or
Boolean OR operator to combine expressions
Not
Negates the included expression
Comparison Expressions To compare properties, use the expressions listed in Table 22-6. The first operator indicates the property that is compared, and the second operator can be a fixed value or another property. Table 22-6 Expressions with two operators
Expression
Description
IsEqualTo
True, if the property is equal to the second operator
IsGreaterThan
True, if the property is greater than the second operator
IsGreaterThanOrEqualTo
True, if the property is greater than or equal to the second operator
IsLessThan
True, if the property is less than the second operator
IsLessThanOrEqualTo
True, if the property is less than or equal to the second operator
IsNotEqualTo
True, if the property is not equal to the second operator
The second operator is embedded in the FieldURIOrConstant element (see Listing 22-8). When comparing with a second property, use FieldURI, IndexedFieldURI, or ExtendendFieldURI instead of Constant. Listing 22-8 Example of the IsGreaterThan expression. 2011-01-01T00:00:00Z
550
Part IV Exchange Server
Additional Expressions Of the additional expressions provided by EWS, Contains (for searching and comparing strings) is the most commonly used. Table 22-7 lists the additional query expressions. Table 22-7 Additional expressions
Expression
Description
Contains
Comparison of strings
Excludes
True, if the bitwise AND operator of the bit mask and the property amount to Zero
Exists
True, if the element has the specified property
Listing 22-9 shows an example of the Contains expression to find all elements whose first name begins with “A”. The search mode is specified with ContainmentMode: full match (FullString), property starts with search text (Prefixed), or the search text is included in the property value (Substring). Use ContainmentComparison to specify how the comparison is performed: exact comparison (Exact), case insensitive (IgnoreCase), ignore diacritical markers (IgnoreNonSpacingCharacters) or a combination of the last two (IgnoreCaseAndNonSpacing Characters). Listing 22-9 Example of the Contains expression. A
Preparation: Modifying the Schema In EWS, Web Services Description Language (WSDL) search expressions are used with replacement groups. To solve the problems that might occur when PHP and EWS interact, you need to modify the web services schema. To do this, perform the following steps:
1. Open the local copy of the types.xsd type schema in an editor.
2. Insert the following lines into the schema (near the end, before the xs:schema end tag).
Chapter 22 Contacts and Search
551
3. Replace all instances with .
4. Change the definition of MultipleOperandBooleanExpressionType, as follows:
Note You need to handle this type in a special way because PHP (currently) ignores the information from maxOccurs relating to groups.
5. Save the schema file. Based on these modifications, PHP generates the correct XML for search expressions in SOAP messages.
552
Part IV Exchange Server
Defining the Search in a Request You specify search expressions for the FindItem and FindFolder operations in the Restriction element. The example shows how to find contacts by using FindItem. Listing 22-10 shows a search for contacts created in 2011 and living in Dreamsville, for which the assistant name property is not set. Listing 22-10 The FindItem operation with search limits. IdOnly
Complete PHP Example Using the following PHP example, you can search for contacts that fall within certain limitations. The example consists of three scripts: the search form, the search parameters for the FindItem operation, and the search and output of the results.
Chapter 22 Contacts and Search
553
The Search Form The search form in Listing 22-11 uses the HTMLPage class (see Appendix A, “Example Scripts and Data”) to create the page and contains the search fields for city, postal code, country, creation date, as well as non-existing fields. Listing 22-11 find-contact-form.php—search form for contacts.
568
Part IV Exchange Server
Figure 23-1 shows the completed form. Notice that the date is entered in the ISO format and the attendees are identified by their email addresses.
Figure 23-1 The completed form to create a meeting.
In Listing 23-8, the form data is evaluated and the CreateItem operation is called. The get MeetingParameters() function creates the parameters for the operation but doesn’t check for errors such as the syntax of date and time. The getValue() function retrieves a form value and getAttendees() creates the array for the attendees by using the mailbox class (see Chapter 21, “Email and Exchange Web Services Basics”). Listing 23-8 Creating a meeting by using the CreateItem operation (create-meeting.php).