php缓存数据到本地缓存,PHP批量请求api并缓存到本地服务器

量比较小的时候速度还不错。当请求量增大之后开始考虑使用curl_multi_init获取数据,于是参照RollingCurl.php写了这样一个多线程的函数。注意:post批量请求注意参数和返回值。

/**

* 批量多线程发送http/https请求,支持post批量请求

* @param $url_arr 请求地址一维数组

* @param $postFields post参数二维数组

* @param $http_headers 附加头部参数二维数组

* @param $cache_dir 本地缓存路径

* @param $cache_time 本地缓存过期时间

* @return array 关联数组,其键code为http状态码,键data为请求返回值

*/

function get_multi_api_contents($url_arr, $postFields = array(), $http_headers = array(), $cache_dir = '', $cache_time = 0)

{

$responses = $lost_urls = $map = array();

//仅当设置了$cache_time时才从缓存中读取

foreach($url_arr as $key => $url)

{

if($cache_time)

{

if(empty($postFields))

{

$cache_path = $cache_dir.'/'.md5($url);

}else{

$cache_path = $cache_dir.'/'.md5($url.serialize($postFields));

}

if(file_exists($cache_path) &&  filemtime($cache_path) + $cache_time > time() && filesize($cache_path) > 0)

{

//如果需要区分从本地缓存和从网络请求可以设置为304或其他http_code

$responses[$url] = array('code'=>200, 'data'=>file_get_contents($cache_path));

}else{

//缓存失效的url缓存

$lost_urls[$key] = array('url' => $url, 'cache' => $cache_path);

}

}else{

$lost_urls[$key] = array('url' => $url, 'cache' => null);

}

}

$queue = curl_multi_init();

foreach($lost_urls as $key => $info)

{

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, $info['url']);

curl_setopt($ch, CURLOPT_TIMEOUT, 30);

curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

if(isset($postFields[$key]))

{

curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields[$key]);

}

curl_setopt($ch, CURLOPT_HEADER, 0);

curl_setopt($ch, CURLOPT_NOSIGNAL, true);

curl_setopt($ch, CURLOPT_ENCODING, 'gzip');

//和设置单个curl请求方式一样,例如

//$default_browser = '';

//curl_setopt($ch, CURLOPT_USERAGENT, $default_browser);

curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);

curl_setopt($ch, CURLOPT_MAXREDIRS, 10);

//https 请求

if(strtolower(substr($info['url'], 0, 5)) == 'https')

{

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

}

if(isset($http_headers[$key]))

{

$headers = array();

foreach($http_headers[$key] as $k => $v)

{

$headers[] = "$k: $v";

}

curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

}

curl_multi_add_handle($queue, $ch);

$map[(string) $ch] = $info['url'];

}

do {

while(($code = curl_multi_exec($queue, $active)) == CURLM_CALL_MULTI_PERFORM);

if($code != CURLM_OK)

{

break;

}

while($done = curl_multi_info_read($queue))

{

$getinfo = curl_getinfo($done['handle']);

$data = curl_multi_getcontent($done['handle']);

$responses[$map[(string) $done['handle']]] = array('code'=>$getinfo['http_code'], 'data'=>$data);

curl_multi_remove_handle($queue, $done['handle']);

curl_close($done['handle']);

}

if($active > 0)

{

curl_multi_select($queue, 0.5);

}

}while($active);

curl_multi_close($queue);

//更新缓存

if($cache_time && !empty($lost_urls))

{

//填补丢失的缓存

foreach($lost_urls as $info)

{

//仅当http_code为200时写入本地缓存

if($responses[$info['url']]['code'] == 200)

{

file_put_contents($info['cache'], $responses[$info['url']]['data']);

}

}

}

return $responses;

}

测试案例://api链接地址数组,支持https请求,使用post请求相同url时请添加无意义参数,例如?r=1

$url_arr = array(

0 => 'https://img.alicdn.com/tps/TB1sXGYIFXXXXc5XpXXXXXXXXXX.jpg?r=1',

1 => 'https://img.alicdn.com/tps/TB1pfG4IFXXXXc6XXXXXXXXXXXX.jpg?r=2',

2 => 'https://img.alicdn.com/tps/TB1h9xxIFXXXXbKXXXXXXXXXXXX.jpg?r=3',

);

//使用post参数时按照$url_arr对应键名提供

$postFields = array();

//使用自定义http头部的时候按照$url_arr对应键名提供

$http_headers = array();

//api请求缓存路径

$cache_dir = __DIR__ .'/cache';

//api请求结果在本地缓存时间,使用post方式请求时需考虑是否设置缓存时间(默认支持post缓存)

$cache_time = 3600;

$results = get_multi_api_contents($url_arr, $postFields, $http_headers, $cache_dir, $cache_time);

主要是为了其他的多线程代码(非curl多并发)中重复请求相同的url时优先从缓存中读取,减小访问新浪接口次数。

考虑到并发不能太高,获得请求结果之后可以从code中判断http响应值是否为200再决定是否重新请求,而且缓存之间相互独立。不过,该方法的性能肯定没有网上的传的《Curl多线程 | X》那么强大,那篇文章给出的curl类请求号称是充分利用CPU和带宽,且支持回调函数,以后需要的时候肯定能派上用场。

转载随意,但请附上文章地址:-)

你可能感兴趣的:(php缓存数据到本地缓存)