Skip to content

Instantly share code, notes, and snippets.

@realshadow
Last active March 14, 2017 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save realshadow/2bb5d6b22f148427fce2e9cbf59a359c to your computer and use it in GitHub Desktop.
Save realshadow/2bb5d6b22f148427fce2e9cbf59a359c to your computer and use it in GitHub Desktop.
Get iCould contacts in PHP; this is just a very quick proof of concept (no error handling, vcard parsing, etc.)
<?php
/**
*
* Only dependency required is "guzzlehttp/guzzle": "~6.0"
*
*/
include 'vendor/autoload.php';
$username = '*****@****.com';
$password = '******';
function authenticate($username, $password)
{
$client = new \GuzzleHttp\Client();
$response = $client->post('https://setup.icloud.com/setup/authenticate/' . $username, [
\GuzzleHttp\RequestOptions::AUTH => func_get_args(),
\GuzzleHttp\RequestOptions::HEADERS => [
'Content-Type' => 'application/xml'
]
]);
if ($response->getStatusCode() !== 200) {
throw new Exception('Unable to login with provided credentials...');
}
$body = json_decode(json_encode(simplexml_load_string($response->getBody()->getContents())), true);
$dsid = $body['dict']['dict'][0]['string'];
$token = $body['dict']['dict'][1]['string'];
return [$dsid, $token];
}
function getLinks($dsid, $token)
{
$data = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<A:propfind xmlns:A="DAV:">
<A:prop>
<A:getetag/>
</A:prop>
</A:propfind>
XML;
$client = new \GuzzleHttp\Client();
$response = $client->request('PROPFIND', 'https://p04-contacts.icloud.com/' . $dsid . '/carddavhome/card', [
\GuzzleHttp\RequestOptions::HEADERS => [
'Depth' => '1',
'Content-Type' => 'text/xml',
'Authorization' => 'X-MobileMe-AuthToken ' . base64_encode(sprintf('%s:%s', $dsid, $token)),
],
\GuzzleHttp\RequestOptions::BODY => $data
]);
$body = json_decode(json_encode(simplexml_load_string($response->getBody()->getContents())), true);
$output = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<F:addressbook-multiget xmlns:F="urn:ietf:params:xml:ns:carddav">
<A:prop xmlns:A="DAV:">
<A:getetag/>
<F:address-data/>
</A:prop>
XML;
foreach ($body['response'] as $item) {
$href = $item['href'];
$output .= <<<XML
<A:href xmlns:A="DAV:">$href</A:href>
XML;
$output .= PHP_EOL;
}
$output .= <<<XML
<A:href xmlns:A="DAV:">$href</A:href>
</F:addressbook-multiget>
XML;
return $output;
}
function getContacts($dsid, $token)
{
$client = new \GuzzleHttp\Client();
$response = $client->request('REPORT', 'https://p04-contacts.icloud.com/' . $dsid . '/carddavhome/card', [
\GuzzleHttp\RequestOptions::HEADERS => [
'Content-Type' => 'text/xml',
'Authorization' => 'X-MobileMe-AuthToken ' . base64_encode(sprintf('%s:%s', $dsid, $token)),
],
\GuzzleHttp\RequestOptions::BODY => getLinks($dsid, $token)
]);
file_put_contents('causeican.txt', $response->getBody()->getContents());
}
[$dsid, $token] = authenticate($username, $password);
getContacts($dsid, $token);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment