Workaround Hi, I thought I would post my temporary workaround. It seems to me that the problem is with the PHP5 soap client. It doesn't seem to handle inheritance too well, at least not in this case. The abstract class "path" is not supposed to be referenced directly, it is used in types.xsd to refer to whichever path you are using be it FieldURI, IndexedFieldURI or ExtendedFieldURI. Just for UpdateItem alone, I created an alternate types.xsd and change line 689 from path to FieldURI or IndexedFieldURI depending on which one I needed to use. This is obviously a hack that could cause problems down the road, but it allows me to finally update items for now. If anyone has more understanding about PHP5 soap and inheritance I would appreciate your thoughts or experiences.
No longer getting the Path error but still failing schema validation I formed this XML, but still have a schema error. It might be something simple, but it's not obvious to me. I haven't looked at your xsd work-around. // Updating Calendar Subjects $UpdateItem->ConflictResolution = "AutoResolve"; $UpdateItem->MessageDisposition = "SaveOnly"; $UpdateItem->ItemChanges->ItemChange->ItemId->Id = $itemids[1]; $UpdateItem->ItemChanges->ItemChange->ItemId->ChangeKey = $changekey[1]; $UpdateItem->ItemChanges->ItemChange->Updates->SetItemField->Path['FieldURI'] = "item:Subject"; $UpdateItem->ItemChanges->ItemChange->Updates->SetItemField->Path['type'] = "PathToUnindexedFieldType"; $UpdateItem->ItemChanges->ItemChange->Updates->SetItemField->CalendarItem->Subject = "Your New Subject"; print_r($UpdateItem); $result = $client->UpdateItem($UpdateItem); Fatal error: Uncaught SoapFault exception: [Client] The request failed schema validation.
After fighting with this solution: http://www.howtoforge.com/talking-soap-with-exchange and getting it to work ( it was a cURL lib problem ). I found all this patching of other classes/lib's etc hard to figure out when there is a problem. Otherwise its works great! anyways this is pure no extra classes or SOAP ( so the wsdl problems doesn't come into play at all ) you don't need to download any files. This code should drop a new message in your inbox. I have only tested on my server but I find this way its quicker to figure out what the problem is. The only down side is you have to generate your own XML, sometimes i find it easier One point is have have to say that figuring out NTLM would have taken me a while but thanks to Manuel Lemos @ http://www.phpclasses.org/browse/package/1888.html i was able to use this NTLM class to do the hard work for me. Code: <?php define("SASL_NTLM_STATE_START", 0); define("SASL_NTLM_STATE_IDENTIFY_DOMAIN", 1); define("SASL_NTLM_STATE_RESPOND_CHALLENGE", 2); define("SASL_NTLM_STATE_DONE", 3); $NTLM = new ntlm_sasl_client_class; echo "<PRE>"; $realm='<IP ADDRESS OF EXCHANGE>'; $workstation=''; $login='<LOGIN NAME>'; $password='<PASSWORD>'; $send_email_to = "[email protected]"; $message=base64_encode(($NTLM->TypeMsg1($realm,$workstation))); # Get the 1st NTLM message from the server $fp = fsockopen("ssl://" . $realm, 443, $errno, $errstr, 30); $httpsend = "GET /EWS/Exchange.asmx HTTP/1.1\r\n"; $httpsend .= "Host: " . $realm . "\r\n"; $httpsend .= "Connection: Keep-Alive\r\n"; $httpsend .= "Accept: */*\r\n"; $httpsend .= "User-Agent: PHP-SOAP-CURL\r\n"; $httpsend .= "Authorization: NTLM " . $message . "\r\n\r\n"; fwrite($fp, $httpsend); $data = ""; while (strpos($data,"\r\n\r\n") == 0) { $data .= fgets($fp, 128); } # Get NTLM string $ntlm = trim(substr($data,strpos($data,"WWW-Authenticate: NTLM ")+22,strpos($data,"\r\n",strpos($data,"WWW-Authenticate: NTLM"))-strpos($data,"WWW-Authenticate: NTLM")-22 )); $ntlm_response=$NTLM->NTLMResponse(substr(base64_decode($ntlm),24,8),$password); $message=base64_encode($NTLM->TypeMsg3($ntlm_response,$login,$realm,$workstation)); $xml = '<?xml version="1.0" encoding="UTF-8"?><SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:ns2="http://schemas.microsoft.com/exchange/services/2006/messages"><SOAP-ENV:Body> <ns2:CreateItem MessageDisposition="SendOnly"> <ns2:SavedItemFolderId> <ns1:DistinguishedFolderId Id="inbox"/> </ns2:SavedItemFolderId><ns2:Items><ns1:Message><ns1:ItemClass>IPM.Note</ns1:ItemClass><ns1:Subject>YOUR SUBJECT</ns1:Subject><ns1:Body BodyType="Text">YOUR BODY TEXT</ns1:Body><ns1:ToRecipients><ns1:Mailbox><ns1:EmailAddress>' . $send_email_to . '</ns1:EmailAddress></ns1:Mailbox></ns1:ToRecipients><ns1:IsRead>true</ns1:IsRead></ns1:Message></ns2:Items></ns2:CreateItem></SOAP-ENV:Body></SOAP-ENV:Envelope>'; $httpsend = "POST /EWS/Exchange.asmx HTTP/1.1\r\n"; $httpsend .= "Host: " . $realm . "\r\n"; $httpsend .= "Connection: Keep-Alive\r\n"; $httpsend .= "Accept: */*\r\n"; $httpsend .= "User-Agent: PHP-SOAP-CURL\r\n"; $httpsend .= "Content-Length: " . strlen($xml) . "\r\n"; $httpsend .= "Content-Type: text/xml; charset=utf-8\r\n"; $httpsend .= "Authorization: NTLM " . $message . "\r\n\r\n"; $httpsend .= $xml; fwrite($fp, $httpsend); $data = ""; while (strpos($data,"\r\n\r\n") == 0) { $data .= fgets($fp, 128); } echo $data; class ntlm_sasl_client_class /* Copyright (c) 2001-2005, Manuel Lemos All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Manuel Lemos nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ { Function ASCIIToUnicode($ascii) { for($unicode="",$a=0;$a<strlen($ascii);$a++) $unicode.=substr($ascii,$a,1).chr(0); return($unicode); } Function TypeMsg1($domain,$workstation) { $domain_length=strlen($domain); $workstation_length=strlen($workstation); $workstation_offset=32; $domain_offset=$workstation_offset+$workstation_length; return( "NTLMSSP\0". "\x01\x00\x00\x00". "\x07\x32\x00\x00". pack("v",$domain_length). pack("v",$domain_length). pack("V",$domain_offset). pack("v",$workstation_length). pack("v",$workstation_length). pack("V",$workstation_offset). $workstation. $domain ); } Function NTLMResponse($challenge,$password) { $unicode=$this->ASCIIToUnicode($password); $md4=mhash(MHASH_MD4,$unicode); $padded=$md4.str_repeat(chr(0),21-strlen($md4)); $iv_size=mcrypt_get_iv_size(MCRYPT_DES,MCRYPT_MODE_ECB); $iv=mcrypt_create_iv($iv_size,MCRYPT_RAND); for($response="",$third=0;$third<21;$third+=7) { for($packed="",$p=$third;$p<$third+7;$p++) $packed.=str_pad(decbin(ord(substr($padded,$p,1))),8,"0",STR_PAD_LEFT); for($key="",$p=0;$p<strlen($packed);$p+=7) { $s=substr($packed,$p,7); $b=$s.((substr_count($s,"1") % 2) ? "0" : "1"); $key.=chr(bindec($b)); } $ciphertext=mcrypt_encrypt(MCRYPT_DES,$key,$challenge,MCRYPT_MODE_ECB,$iv); $response.=$ciphertext; } return $response; } Function TypeMsg3($ntlm_response,$user,$domain,$workstation) { $domain_unicode=$this->ASCIIToUnicode($domain); $domain_length=strlen($domain_unicode); $domain_offset=64; $user_unicode=$this->ASCIIToUnicode($user); $user_length=strlen($user_unicode); $user_offset=$domain_offset+$domain_length; $workstation_unicode=$this->ASCIIToUnicode($workstation); $workstation_length=strlen($workstation_unicode); $workstation_offset=$user_offset+$user_length; $lm=""; $lm_length=strlen($lm); $lm_offset=$workstation_offset+$workstation_length; $ntlm=$ntlm_response; $ntlm_length=strlen($ntlm); $ntlm_offset=$lm_offset+$lm_length; $session=""; $session_length=strlen($session); $session_offset=$ntlm_offset+$ntlm_length; return( "NTLMSSP\0". "\x03\x00\x00\x00". pack("v",$lm_length). pack("v",$lm_length). pack("V",$lm_offset). pack("v",$ntlm_length). pack("v",$ntlm_length). pack("V",$ntlm_offset). pack("v",$domain_length). pack("v",$domain_length). pack("V",$domain_offset). pack("v",$user_length). pack("v",$user_length). pack("V",$user_offset). pack("v",$workstation_length). pack("v",$workstation_length). pack("V",$workstation_offset). pack("v",$session_length). pack("v",$session_length). pack("V",$session_offset). "\x01\x02\x00\x00". $domain_unicode. $user_unicode. $workstation_unicode. $lm. $ntlm ); } }; ?>
My Changes Hopefully this will help someone... I use Intermedia Managed Exchange. I was Having trouble with the WSDL File caching all the time. Add this line to your code to disable WSDL Caching - ini_set("soap.wsdl_cache_enabled", "0"); In the WSDL file I removed the last line - "</wsdl:definitions>" and then pasted Eric's code as per his great tutorial - "<wsdl:service name="ExchangeServices"> <wsdlort name="ExchangeServicePort" binding="tns:ExchangeServiceBinding"> <soap:address location="https://exchange.example.com/EWS/Exchange.asmx"/> </wsdlort> </wsdl:service> </wsdl:definitions>" Dont forget to change the SOAP:ADDRESS LOCATION to https://<yourexchangeOWAdomain>/EWS/Exchange.asmx
Any Update on UpdateItem Greetings, I've tried a whole bunch of things wrt UpdateItem, but no success like I see here. jmclen what did you change the types.xsd file line 689 to? I've tried a few variations and can not make it work. Thanks! UPDATE: jmclen's solution worked for me, I had something caching which was throwing me off, just replacing the tath with t:FieldURI is what I needed.
Not able to Fetch emails Hello , I am a newbie to this forum, first i would like to thank for great artical on How to talk to Exchange using SOAP. Here i am able to send emails using Exchange web service. but my requirment is to fetch emails from particular user and display from address, Body and subject line. When i tried to filter get folder details it throws following error; error is on the line marked with bold and blue color. This is very urgent as i am working towards a dedline for a customer. any help would be appriciated. Thanks for your help in advance. This is my code. $FindFolder->Traversal = 'Shallow'; $FindFolder->FolderShape->BaseShape = 'AllProperties'; $FindFolder->Traversal->ParentFolderIds->DistinguishedFolderId->Id = 'root'; $result = $client->FindFolder($FindFolder); $folders = $result->ResponseMessages->FindFolderResponseMessage->RootFolder->Folders->Folder; foreach ($folders as $folder) { if ('Top of Information Store' == $folder->DisplayName) { $tois_folder = $folder; } } Fatal error: Uncaught SoapFault exception: [soap11:Client] The request failed schema validation: The element 'FindFolder' in namespace 'http://schemas.microsoft.com/exchange/services/2006/messages' has incomplete content. List of possible elements expected: 'IndexedPageFolderView, FractionalPageFolderView, Restriction, ParentFolderIds' in namespace 'http://schemas.microsoft.com/exchange/services/2006/messages'. in C:\opensource_project_zone\ews\index.php:154 Stack trace: #0 [internal function]: SoapClient->__call('FindFolder', Array) #1 C:\opensource_project_zone\ews\index.php(154): ExchangeNTLMSoapClient->FindFolder(Object(stdClass)) #2 {main} thrown in C:\opensource_project_zone\ews\index.php on line 154
Hello, first, sorry for my bad english the second. thanks für the great class to connect exchange2007 with php. it works great, but.... .... how can i list the inbox of my mailbox. a list of the calendar PHP: $FindItem->Traversal = "Shallow"; $FindItem->ItemShape->BaseShape = "AllProperties"; $FindItem->ParentFolderIds->DistinguishedFolderId->Id = "calendar"; $FindItem->CalendarView->StartDate = $s_start; $FindItem->CalendarView->EndDate = $s_ende; $result = $client->FindItem($FindItem); $calendaritems = $result->ResponseMessages->FindItemResponseMessage->RootFolder->Items->CalendarItem; if($debug) { print_r($calendaritems); } foreach($calendaritems as $item) { echo $item->Subject } can anyone tell me the code for the list of inbox? best regards Werner
Hi, sorry for pulling out this old thread, but I have a problem with passing the body attributes for CreateItem: I have successfully made a connection to the Exchange-server and was able to create an appointment (with the code from the tutorial). But there is the problem: I wrote a simple test script for this and after the test I put this into a class. In the testscript everything was fine and working, but in the class where I added a addAppointment()-function, I'm getting an error at this line: PHP: $CreateItem->Items->CalendarItem[0]->Body[_] = $text; Error: Use of undefined constant _ - assumed '_'. This is the function: PHP: public function addAppointment( $path, $title, $text, $start, $end, $allday = false, $busystatus = 'Free', $location = '', $category = '' ) { // get ids for directory $ids = $this->getFolderIDsByPath($path);// <simple function for getting id/changekey for given path, not interesting here if ( $ids ) { $CreateItem->SavedItemFolderId->FolderId->Id = $ids['Id']; $CreateItem->SavedItemFolderId->FolderId->ChangeKey = $ids['ChangeKey']; $CreateItem->Items->CalendarItem = array(); $CreateItem->SendMeetingInvitations = "SendToNone"; $CreateItem->Items->CalendarItem[0]->Subject = $title; $CreateItem->Items->CalendarItem[0]->Start = $start; # ISO date format. Z denotes UTC time $CreateItem->Items->CalendarItem[0]->End = $end; $CreateItem->Items->CalendarItem[0]->Body[_] = $text; // < error here $CreateItem->Items->CalendarItem[0]->Body['BodyType']="Text"; $CreateItem->Items->CalendarItem[0]->IsAllDayEvent = $allday; $CreateItem->Items->CalendarItem[0]->LegacyFreeBusyStatus = $busystatus; $CreateItem->Items->CalendarItem[0]->Location = $location; $CreateItem->Items->CalendarItem[0]->Categories->String = $category; $result = $this->client->CreateItem($CreateItem); // < $this->client holds SOAP-client object print_r($result); if ( $result->ResponseMessages->CreateItemResponseMessage->ResponseClass == 'Success' ) { // return id/changekey for saving somewhere to be able to edit the appointment return array( 'Id' => $result->ResponseMessages->CreateItemResponseMessage->Items->CalendarItem->ItemId->Id, 'ChangeKey' => $result->ResponseMessages->CreateItemResponseMessage->Items->CalendarItem->ItemId->ChangeKey, ); } return null; } } Can somebody tell me whats wrong? Why is this working in the one script and not in the other? Both are on the same server (Ubuntu 9.04, Apache 2.2.11, PHP 5.2.6). How can I get this working? I'm looking at this all the day but I couldn't figure it out. Thank you in advance for your help! EDIT: OK, found something: if I change PHP: $CreateItem->Items->CalendarItem[0]->Body[_] = $text; to PHP: $CreateItem->Items->CalendarItem[0]->Body[] = $text; it works and the appointment appears in the calendar, but the body is not saved . best regards marv hope my english is not to bad
Hi, I come to you because I have a big problem that is urgent, for one of my projects at work. I'm stuck and it becomes very urgent, I seek a way to list all the emails in my inbox from an Exchange server and read the emails and their headers ,.... I use the EWS Class an LDAP connection with the exchange server, I can send emails, sort and add events to the calendar and enter in the inbox (I have the number of mail and the total number of mail unread) Could you please help me Thank you in advance