<?php
/****************************************
* @author @tonyshowoff
* @version 1
* @license MIT/X11
****************************************/
$GLOBALS['_EXCHANGE'] = array(
'impersonate' => Null, /* Email address of account to impersonate */
'curl' => Null,
'full_debug' => False, /* This will display all traffic as well */
'curl_debug' => False /* Set cURL as verbose response */
);
$GLOBALS['_CONFIG'] = array(
'debug_mode' => True,
'exchange_cache' => '', /* Pathh which contains your Services.wsdl, etc */
);
class Exchange {
public $lastError;
private $client;
private $impersonate;
private $pass;
private $user;
private $wsdl;
function __construct($user, $pass, $impersonate = Null) {
$this->wsdl = $GLOBALS['_CONFIG']['exchange_cache'] . '/Services.wsdl';
$this->user = $user;
$this->pass = $pass;
$this->impersonate = $impersonate;
$GLOBALS['_EXCHANGE']['impersonate'] = $impersonate;
$GLOBALS['_EXCHANGE']['curl'] = Null;
$this->client = new ExchangeNTLMSoapClient($this->wsdl);
$this->client->user = $this->user;
$this->client->password = $this->pass;
}
function calendarEntry($id) {
$this->setup();
$req_xml = new stdClass();
$req_xml->ItemShape = new stdClass();
$req_xml->ItemShape->BaseShape = 'AllProperties';
$req_xml->ItemIds = new stdClass();
$req_xml->ItemIds->ItemId = new stdClass();
$req_xml->ItemIds->ItemId->Id = $id;
try {
$response = $this->client->GetItem($req_xml);
} catch (Exception $e) {
echo 'calendarEntry() exception on ID "' . $id . '": ', $e->getMessage(), "\n";
$this->teardown();
return False;
}
$this->teardown();
if ($response->ResponseMessages->GetItemResponseMessage->ResponseCode == 'NoError') {
return $response->ResponseMessages->GetItemResponseMessage->Items->CalendarItem;
} else {
return False;
}
}
function calendarEventAdd($subject, $start, $end, $location, $body = '', $type = 'HTML', $isallday = False) {
/*
$start and $end must be in ISO date format or rather 'c' in PHP date format
This function returns an array of item details upon success and False upon failure. */
$this->setup();
$event_xml = new stdClass();
$event_xml->SendMeetingInvitations = 'SendToNone';
$event_xml->SavedItemFolderId = new stdClass();
$event_xml->SavedItemFolderId->DistinguishedFolderId = new stdClass();
$event_xml->SavedItemFolderId->DistinguishedFolderId->Id = 'calendar';
$event_xml->Items = new stdClass();
$event_xml->Items->CalendarItem = new stdClass();
$event_xml->Items->CalendarItem->Subject = $subject;
$event_xml->Items->CalendarItem->Start = $start;
$event_xml->Items->CalendarItem->End = $end;
$event_xml->Items->CalendarItem->Body = new stdClass();
$event_xml->Items->CalendarItem->Body->BodyType = $type;
$event_xml->Items->CalendarItem->Body->_ = $body;
$event_xml->Items->CalendarItem->IsAllDayEvent = $isallday;
$event_xml->Items->CalendarItem->LegacyFreeBusyStatus = 'Busy'; // Legacy only (never use)
$event_xml->Items->CalendarItem->Location = $location;
try {
$response = $this->client->CreateItem($event_xml);
} catch (Exception $e) {
echo 'calendarEventAdd() exception: ', $e->getMessage(), "\n";
$this->teardown();
return False;
}
$this->teardown();
if ($response->ResponseMessages->CreateItemResponseMessage->ResponseCode == 'NoError') {
return ['ItemId' => $response->ResponseMessages->CreateItemResponseMessage->Items->CalendarItem->ItemId->Id,
'ChangeKey' => $response->ResponseMessages->CreateItemResponseMessage->Items->CalendarItem->ItemId->ChangeKey];
} else {
$this->lastError = $response->ResponseMessages->CreateItemResponseMessage->ResponseCode;
log_out_error('exchange', "Calendar:\r\nError: " . print_r($this->lastError, 1) . "\r\n\r\nInitial data:\r\n" . print_r($event_xml, 1));
return False;
}
}
/**
* Sets up strream handling. Internally used.
*
* @access private
* @return void
*/
private function setup() {
stream_wrapper_unregister('http');
stream_wrapper_register('http', 'ExchangeNTLMStream') or die('Failed to register protocol: 8c251e34-77e6-41ce-88da-4dbc90bc8a60');
}
/**
* Tears down stream handling. Internally used.
*
* @access private
* @return void
*/
function teardown() {
stream_wrapper_restore('http');
}
function calendarEventDelete($item_id, $type = 'HardDelete') {
$this->setup();
$DeleteItem = new stdClass();
$DeleteItem->DeleteType = $type;
$DeleteItem->SendMeetingCancellations = 'SendToNone';
$DeleteItem->ItemIds = new stdClass();
$DeleteItem->ItemIds->ItemId = new stdClass();
$DeleteItem->ItemIds->ItemId->Id = $item_id;
try {
$response = $this->client->DeleteItem($DeleteItem);
} catch (Exception $e) {
echo 'calendarEventDelete() exception on ID "' . $item_id . '": ', $e->getMessage(), "\n";
$this->teardown();
return False;
}
$this->teardown();
if ($response->ResponseMessages->DeleteItemResponseMessage->ResponseCode == 'NoError') {
return True;
} else {
$this->lastError = $response->ResponseMessages->DeleteItemResponseMessage->ResponseCode;
log_out_error('exchange', "Calendar:\r\nError: " . print_r($this->lastError, 1) . "\r\n\r\nInitial data:\r\n" . print_r($DeleteItem, 1));
return False;
}
}
function calendarList($limit = 10, $offset = 0, $full = False, $point = 'Beginning') {
$this->setup();
$FindItem = new stdClass();
$FindItem->Traversal = 'Shallow';
$FindItem->ItemShape = new stdClass();
if (True == $full) {
$FindItem->ItemShape->BaseShape = 'AllProperties';
} else {
$FindItem->ItemShape->BaseShape = 'IdOnly';
$FindItem->ItemShape->AdditionalProperties = new SoapVar(
'<ns1:AdditionalProperties>
<ns1:FieldURI FieldURI="calendar:CalendarItemType"/>
<ns1:FieldURI FieldURI="calendar:IsMeeting"/>
<ns1:FieldURI FieldURI="calendar:IsRecurring"/>
<ns1:FieldURI FieldURI="calendar:Organizer"/>
<ns1:FieldURI FieldURI="calendar:Start"/>
<ns1:FieldURI FieldURI="calendar:End"/>
<ns1:FieldURI FieldURI="calendar:Duration"/>
<ns1:FieldURI FieldURI="calendar:IsAllDayEvent"/>
<ns1:FieldURI FieldURI="calendar:Location"/>
<ns1:FieldURI FieldURI="calendar:MeetingRequestWasSent"/>
<ns1:FieldURI FieldURI="calendar:MyResponseType"/>
<ns1:FieldURI FieldURI="calendar:AppointmentSequenceNumber"/>
<ns1:FieldURI FieldURI="calendar:AppointmentState"/>
<ns1:FieldURI FieldURI="item:Categories"/>
<ns1:FieldURI FieldURI="item:HasAttachments"/>
<ns1:FieldURI FieldURI="item:ReminderDueBy"/>
<ns1:FieldURI FieldURI="item:ReminderIsSet"/>
<ns1:FieldURI FieldURI="item:ReminderMinutesBeforeStart"/>
<ns1:FieldURI FieldURI="item:Subject"/>
<ns1:FieldURI FieldURI="item:ItemClass"/>
<ns1:FieldURI FieldURI="item:Sensitivity"/>
<ns1:FieldURI FieldURI="item:DateTimeReceived"/>
<ns1:FieldURI FieldURI="item:Importance"/>
<ns1:FieldURI FieldURI="item:IsDraft"/>
<ns1:FieldURI FieldURI="item:DateTimeCreated"/>
</ns1:AdditionalProperties>', XSD_ANYXML);
}
$FindItem->IndexedPageItemView = new stdClass();
$FindItem->IndexedPageItemView->MaxEntriesReturned = $limit;
$FindItem->IndexedPageItemView->Offset = $offset;
$FindItem->IndexedPageItemView->BasePoint = $point;
$FindItem->ParentFolderIds = new stdClass();
$FindItem->ParentFolderIds->DistinguishedFolderId = new stdClass();
$FindItem->ParentFolderIds->DistinguishedFolderId->Id = 'calendar';
try {
$response = $this->client->FindItem($FindItem);
} catch (Exception $e) {
return False;
}
if ($response->ResponseMessages->FindItemResponseMessage->ResponseCode != 'NoError') {
$this->lastError = $response->ResponseMessages->FindItemResponseMessage->ResponseCode;
return false;
}
if (empty($response->ResponseMessages->FindItemResponseMessage->RootFolder->Items->CalendarItem)) {
$items = False;
} else {
$items = $response->ResponseMessages->FindItemResponseMessage->RootFolder->Items->CalendarItem;
if (!is_array($items)) {
$items = $response->ResponseMessages->FindItemResponseMessage->RootFolder->Items;
}
}
$this->teardown();
return $items;
}
function calendar_event_update($item_id, $changekey, $subject, $start, $end, $location, $body = '', $type = 'HTML', $isallday = False) {
/*
$start and $end must be in ISO date format or rather 'c' in PHP date format
This function returns an array of item details upon success and False upon failure. */
$this->setup();
$update_xml = new stdClass();
$update_xml->SendMeetingInvitationsOrCancellations = 'SendToNone';
$update_xml->MessageDisposition = 'SaveOnly';
$update_xml->ConflictResolution = 'AlwaysOverwrite';
$update_xml->ItemChanges = new stdClass();
$update_xml->ItemChanges->ItemChange = new stdClass();
$update_xml->ItemChanges->ItemChange->ItemId = new stdClass();
$update_xml->ItemChanges->ItemChange->ItemId->Id = $item_id;
$update_xml->ItemChanges->ItemChange->ItemId->ChangeKey = $changekey;
$update_xml->ItemChanges->ItemChange->Updates = new stdClass();
$update_xml->ItemChanges->ItemChange->Updates = new SoapVar(
'<ns1:Updates>
<ns1:SetItemField>
<ns1:FieldURI FieldURI="item:Subject" />
<ns1:CalendarItem>
<ns1:Subject>' . htmlspecialchars($subject) . '</ns1:Subject>
</ns1:CalendarItem>
</ns1:SetItemField>
<ns1:SetItemField>
<ns1:FieldURI FieldURI="calendar:Location" />
<ns1:CalendarItem>
<ns1:Location>' . htmlspecialchars($location) . '</ns1:Location>
</ns1:CalendarItem>
</ns1:SetItemField>
<ns1:SetItemField>
<ns1:FieldURI FieldURI="calendar:Start" />
<ns1:CalendarItem>
<ns1:Start>' . $start . '</ns1:Start>
</ns1:CalendarItem>
</ns1:SetItemField>
<ns1:SetItemField>
<ns1:FieldURI FieldURI="calendar:End" />
<ns1:CalendarItem>
<ns1:End>' . $end . '</ns1:End>
</ns1:CalendarItem>
</ns1:SetItemField>
<ns1:SetItemField>
<ns1:FieldURI FieldURI="item:Body" />
<ns1:CalendarItem>
<ns1:Body BodyType="HTML">' . htmlspecialchars($body) . '</ns1:Body>
</ns1:CalendarItem>
</ns1:SetItemField>
</ns1:Updates>', XSD_ANYXML);
try {
$response = $this->client->UpdateItem($update_xml);
} catch (Exception $e) {
echo 'calendar_event_update() exception on ID "' . $item_id . '": ', $e->getMessage(), "\n";
$this->teardown();
return False;
}
$this->teardown();
if ($response->ResponseMessages->UpdateItemResponseMessage->ResponseCode == 'NoError') {
return ['changekey' => $response->ResponseMessages->UpdateItemResponseMessage->Items->CalendarItem->ItemId->ChangeKey];
} else {
$this->lastError = $response->ResponseMessages->UpdateItemResponseMessage->ResponseCode;
log_out_error('exchange', "Calendar:\r\nError: " . print_r($this->lastError, 1) . "\r\n\r\nInitial data:\r\n" . print_r($update_xml, 1));
return False;
}
}
function close() {
curl_close($GLOBALS['_EXCHANGE']['curl']);
$GLOBALS['_EXCHANGE']['impersonate'] = Null;
$GLOBALS['_EXCHANGE']['curl'] = Null;
if ($GLOBALS['_CONFIG']['debug_mode'] == True) {
echo " [D] Close Exchange connection.\n";
}
}
/**
* Deletes a message in the mailbox of the current user.
*
* @access public
*
* @param ItemId $ItemId (such as one returned by get_messages)
* @param string $deletetype . (default: "HardDelete")
*
* @return bool $success (true: message was deleted, false: message failed to delete)
*/
function delete_message($ItemId, $deletetype = "HardDelete") {
$this->setup();
$DeleteItem->DeleteType = $deletetype;
$DeleteItem->ItemIds->ItemId = $ItemId;
$response = $this->client->DeleteItem($DeleteItem);
$this->teardown();
if ($response->ResponseMessages->DeleteItemResponseMessage->ResponseCode == "NoError") {
return true;
} else {
$this->lastError = $response->ResponseMessages->DeleteItemResponseMessage->ResponseCode;
return false;
}
}
function getAttachment($item_id, $attachment_id) {
// Doesn't seem to work.
$this->setup();
$req_xml = new stdClass();
$req_xml->ItemShape = new stdClass();
$req_xml->ItemShape->BaseShape = 'AllProperties';
$req_xml->ItemIds = new stdClass();
$req_xml->ItemIds->ItemId = new stdClass();
$req_xml->ItemIds->ItemId->Id = $item_id;
$req_xml->ItemIds->ItemId->AttachmentId = $attachment_id;
try {
$response = $this->client->GetAttachment($req_xml);
} catch (Exception $e) {
echo 'getAttachment() exception on ID "' . $item_id . '": ', $e->getMessage(), "\n";
$this->teardown();
return False;
}
$this->teardown();
if ($response->ResponseMessages->GetItemResponseMessage->ResponseCode == 'NoError') {
return $response->ResponseMessages->GetItemResponseMessage->Items->Attachment;
} else {
return False;
}
}
function getInbox($limit = 10, $offset = 0) {
$this->setup();
$FindItem = new stdClass();
$FindItem->Traversal = 'Shallow';
$FindItem->ItemShape = new stdClass();
$FindItem->ItemShape->BaseShape = 'IdOnly';
$FindItem->ItemShape->AdditionalProperties = new SoapVar(
'<ns1:AdditionalProperties>
<ns1:FieldURI FieldURI="item:Subject"/>
</ns1:AdditionalProperties>', XSD_ANYXML);
$FindItem->IndexedPageItemView = new stdClass();
$FindItem->IndexedPageItemView->MaxEntriesReturned = $limit;
$FindItem->IndexedPageItemView->Offset = $offset;
$FindItem->IndexedPageItemView->BasePoint = 'Beginning';
$FindItem->ParentFolderIds = new stdClass();
$FindItem->ParentFolderIds->DistinguishedFolderId = new stdClass();
$FindItem->ParentFolderIds->DistinguishedFolderId->Id = 'inbox';
try {
$response = $this->client->FindItem($FindItem);
} catch (Exception $e) {
return False;
}
if ($response->ResponseMessages->FindItemResponseMessage->ResponseCode != 'NoError') {
$this->lastError = $response->ResponseMessages->FindItemResponseMessage->ResponseCode;
return false;
}
$items = $response->ResponseMessages->FindItemResponseMessage->RootFolder->Items->Message;
$this->teardown();
return $items;
}
function itemExists($id) {
$this->setup();
$req_xml = new stdClass();
$req_xml->ItemShape = new stdClass();
$req_xml->ItemShape->BaseShape = 'IdOnly';
$req_xml->ItemIds = new stdClass();
$req_xml->ItemIds->ItemId = new stdClass();
$req_xml->ItemIds->ItemId->Id = $id;
try {
$response = $this->client->GetItem($req_xml);
} catch (Exception $e) {
echo 'itemExists() exception on ID "' . $id . '": ', $e->getMessage(), "\n";
return False;
}
$this->teardown();
if ($response->ResponseMessages->GetItemResponseMessage->ResponseCode == 'NoError') {
return True;
} else {
return False;
}
}
function sendMessage($to, $subject, $content, $type = 'HTML', $save = False, $read = True) {
/*
This sends a message through Exchange as the user that's logged in via init.
$to - The email address we're sending to, can be internal or external
$subject - The subject
$content - The content, style dependent on $type
$type - Default is 'Text', but 'HTML' should be used for HTML emails
$save - Default F, T/F save to user's sent folder?
$read - Default F, T/F mark as read. @BUG: Doesn't seem to work, possibly missing another field?
*/
$this->setup();
$msg_xml = new stdClass();
if ($save == True) {
$msg_xml->MessageDisposition = 'SendOnly';
$msg_xml->SavedItemFolderId = new stdClass();
$msg_xml->SavedItemFolderId->DistinguishedFolderId = new stdClass();
$msg_xml->SavedItemFolderId->DistinguishedFolderId->Id = 'sentitems';
} else {
$msg_xml->MessageDisposition = 'SendOnly';
}
$msg_xml->Items = new stdClass();
$msg_xml->Items->Message = new stdClass();
$msg_xml->Items->Message->ItemClass = 'IPM.Note';
$msg_xml->Items->Message->Subject = $subject;
$msg_xml->Items->Message->Body = new stdClass();
$msg_xml->Items->Message->Body->BodyType = $type;
$msg_xml->Items->Message->Body->_ = $content;
$msg_xml->Items->Message->ToRecipients = new stdClass();
$msg_xml->Items->Message->ToRecipients->Mailbox = new stdClass();
$msg_xml->Items->Message->ToRecipients->Mailbox->EmailAddress = $to;
if ($read == True) {
$msg_xml->Items->Message->IsRead = 'true';
}
try {
$response = $this->client->CreateItem($msg_xml);
} catch (Exception $e) {
return False;
}
$this->teardown();
if ($response->ResponseMessages->CreateItemResponseMessage->ResponseCode == 'NoError') {
return True;
} else {
$this->lastError = $response->ResponseMessages->CreateItemResponseMessage->ResponseCode;
log_out_error('exchange', "sendMessage:\r\nError: " . print_r($this->lastError, 1) . "\r\n\r\nInitial data:\r\n" . print_r($msg_xml, 1));
return False;
}
}
}
class ExchangeNTLMSoapClient extends NTLMSoapClient {
public $password = '';
public $user = '';
}
class ExchangeNTLMStream extends NTLMStream {
//protected $user = '';
//protected $password = '';
}
class ImpersonationHeader {
var $ConnectingSID;
/*ExchangeImpersonationType and the
ConnectingSIDType*/
function __construct($email) {
$this->ConnectingSID = new stdClass();
$this->ConnectingSID->PrincipalName = $email;
/*
$this->ConnectingSID = new stdClass();
$this->ConnectingSID->PrimarySmtpAddress = $email;
*/
}
}
class NTLMSoapClient extends SoapClient {
function __doRequest($request, $location, $action, $version, $one_way = 0) {
if ($GLOBALS['_EXCHANGE']['full_debug'] == True) {
echo 'Request: ' . $request . "\n<br />";
echo 'Location: ' . $location . "\n<br />";
echo 'Action: ' . $action . "\n<br />";
echo 'Version: ' . $version . "\n<br />";
echo 'One-way: ' . $one_way . "\n<br />";
echo 'Request: ' . print_r($request, 1);
}
$headers = [
'Method: POST',
'Connection: Keep-Alive',
'User-Agent: PHP-SOAP-CURL',
'Content-Type: text/xml; charset=utf-8',
'SOAPAction: "' . $action . '"',
];
// @TODO: Somehow we need to pass the $impersonate var
// from the exchange class to here, probably just in init
// or something, but we'll do this hack for now.
if ($GLOBALS['_EXCHANGE']['impersonate'] != Null) {
// @TODO / @HACK: Ideally we'd want to just use the SOAP system
// built into PHP to do this, but it has a flaw which
// will not let you properly impersonate someone.
// Until it's fixed (been 2 years as of now) we do this.
$xml = '<SOAP-ENV:Header>';
$xml .= '<ns1:ExchangeImpersonation>';
$xml .= '<ns1:ConnectingSID>';
$xml .= '<ns1:PrimarySmtpAddress>' . $GLOBALS['_EXCHANGE']['impersonate'] . '</ns1:PrimarySmtpAddress>';
$xml .= '</ns1:ConnectingSID>';
$xml .= '</ns1:ExchangeImpersonation>';
$xml .= '</SOAP-ENV:Header>';
$request = str_replace('><SOAP-ENV:Body', '>' . $xml . '<SOAP-ENV:Body', $request);
}
$this->__last_request_headers = $headers;
$GLOBALS['_EXCHANGE']['curl'] = curl_init($location);
curl_setopt($GLOBALS['_EXCHANGE']['curl'], CURLOPT_RETURNTRANSFER, true);
curl_setopt($GLOBALS['_EXCHANGE']['curl'], CURLOPT_HTTPHEADER, $headers);
curl_setopt($GLOBALS['_EXCHANGE']['curl'], CURLOPT_POST, true);
curl_setopt($GLOBALS['_EXCHANGE']['curl'], CURLOPT_POSTFIELDS, $request);
curl_setopt($GLOBALS['_EXCHANGE']['curl'], CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($GLOBALS['_EXCHANGE']['curl'], CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
curl_setopt($GLOBALS['_EXCHANGE']['curl'], CURLOPT_USERPWD, $this->user . ':' . $this->password);
curl_setopt($GLOBALS['_EXCHANGE']['curl'], CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($GLOBALS['_EXCHANGE']['curl'], CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($GLOBALS['_EXCHANGE']['curl'], CURLOPT_VERBOSE, $GLOBALS['_EXCHANGE']['curl_debug']);
$response = curl_exec($GLOBALS['_EXCHANGE']['curl']);
if ($GLOBALS['_EXCHANGE']['full_debug'] == True) {
echo 'Response: ' . print_r($response, 1);
}
// @TODO: If there's an error we need to log it, but
// this may need to be done at all the functions
// which parse this, rather than here. Though we
// should still log all CURL errors.
return $response;
}
function __getLastRequestHeaders() {
return implode("n", $this->__last_request_headers) . "n";
}
}
class NTLMStream {
private $buffer;
private $mode;
private $opened_path;
private $options;
private $path;
private $pos;
public function stream_close() {
echo "[NTLMStream::stream_close] n";
curl_close($this->ch);
}
public function stream_eof() {
echo "[NTLMStream::stream_eof] ";
if ($this->pos > strlen($this->buffer)) {
echo "true n";
return true;
}
echo "false n";
return false;
}
public function stream_flush() {
echo "[NTLMStream::stream_flush] n";
$this->buffer = null;
$this->pos = null;
}
public function stream_open($path, $mode, $options, $opened_path) {
echo "[NTLMStream::stream_open] $path , mode=$mode n";
$this->path = $path;
$this->mode = $mode;
$this->options = $options;
$this->opened_path = $opened_path;
$this->createBuffer($path);
return true;
}
private function createBuffer($path) {
if ($this->buffer) {
return;
}
echo "[NTLMStream::createBuffer] create buffer from : $pathn";
$this->ch = curl_init($path);
curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($this->ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
curl_setopt($this->ch, CURLOPT_HTTPAUTH, CURLAUTH_NTLM);
curl_setopt($this->ch, CURLOPT_USERPWD, $this->user . ':' . $this->password);
echo $this->buffer = curl_exec($this->ch);
echo "[NTLMStream::createBuffer] buffer size : " . strlen($this->buffer) . "bytesn";
$this->pos = 0;
}
/* return the position of the current read pointer */
public function stream_read($count) {
echo "[NTLMStream::stream_read] $count n";
if (strlen($this->buffer) == 0) {
return false;
}
$read = substr($this->buffer, $this->pos, $count);
$this->pos += $count;
return $read;
}
public function stream_stat() {
echo "[NTLMStream::stream_stat] n";
$this->createBuffer($this->path);
$stat = [
'size' => strlen($this->buffer),
];
return $stat;
}
public function stream_tell() {
echo "[NTLMStream::stream_tell] n";
return $this->pos;
}
public function stream_write($data) {
echo "[NTLMStream::stream_write] n";
if (strlen($this->buffer) == 0) {
return false;
}
return true;
}
/* Create the buffer by requesting the url through cURL */
public function url_stat($path, $flags) {
echo "[NTLMStream::url_stat] n";
$this->createBuffer($path);
$stat = [
'size' => strlen($this->buffer),
];
return $stat;
}
}
class UpdateResponse {
}
?>