Skip to content

Instantly share code, notes, and snippets.

@SamuelDavis
Last active June 21, 2019 01:18
Show Gist options
  • Save SamuelDavis/35d2c3a9908f3090e9e7a29f481bd1cc to your computer and use it in GitHub Desktop.
Save SamuelDavis/35d2c3a9908f3090e9e7a29f481bd1cc to your computer and use it in GitHub Desktop.
Implementation of async url fetching using curl (with laravel Cache-facade caching)
<?php
function urlToHtml(string ...$urls)
{
$cache = array_map('sha1', $urls);
$ttl = array_fill(0, count($urls), null);
$res = [];
$ch = [];
$mh = curl_multi_init();
$options = [
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
];
foreach ($urls as $i => $url) {
if (Cache::has($cache[$i])) {
$res[$i] = Cache::get($cache[$i]);
} else {
$ch[$i] = curl_init($url);
curl_setopt_array($ch[$i], $options);
curl_multi_add_handle($mh, $ch[$i]);
}
}
do {
if (curl_multi_select($mh) !== -1) {
usleep(100);
}
do {
$execReturnValue = curl_multi_exec($mh, $runningHandles);
} while ($execReturnValue === CURLM_CALL_MULTI_PERFORM);
} while ($runningHandles && $execReturnValue === CURLM_OK);
if ($execReturnValue != CURLM_OK) {
trigger_error("Curl multi read error $execReturnValue\n", E_USER_WARNING);
}
foreach ($urls as $i => $url) {
if (!array_key_exists($i, $ch)) {
continue;
}
$curlError = curl_error($ch[$i]);
if ($curlError === '') {
$responseContent = curl_multi_getcontent($ch[$i]);
$res[$i] = $responseContent;
Cache::put($cache[$i], $responseContent, $ttl[$i]);
} else {
trigger_error("Curl error on handle $i: $curlError\n", E_USER_WARNING);
}
curl_multi_remove_handle($mh, $ch[$i]);
curl_close($ch[$i]);
}
curl_multi_close($mh);
return count($urls) === 1 ? reset($res) : $res;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment