我一直在努力为自己创建一个快速的 Twitter 小部件以供重复使用,只是一些简单的东西,用于缓存来自公共 API 的数据。由于 twitter 只允许 X 个请求在某个时间段内,并且我一直在共享主机上对此进行测试,因此我经常用完请求并且 Twitter 拒绝我的请求。因此,在写入更新的缓存文件之前,我首先检查我的请求是否被拒绝。
不幸的是,我似乎不时丢失此文件,因为我经常看到"临时文件未写入"消息。仅当文件不存在时才应显示。
这是完整的 php 函数:
function getTweets($num)
{
$cfile = sys_get_temp_dir().'/e1z'. $type . md5 ( 'something' );
if (is_file ( $cfile ) == false) {
$cfile_time = strtotime ( '1983-04-30 07:15:00' );
} else {
$cfile_time = filemtime ( $cfile );
}
$difference = strtotime ( date ( 'Y-m-d H:i:s' ) ) - $cfile_time;
if ($difference >= 100) {
$tags = array("created_at", "text", "screen_name", "profile_image_url"); // twitter names
$local = array("time", "msg", "user", "image"); // local names
$reader = new XMLReader();
$url = 'http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=boriskourt&include_rts=true&count=' . $num;
$headers = get_headers($url, 1);
if ($headers[0] == 'HTTP/1.0 400 Bad Request'){
if (is_file ( $cfile ) == true) {
$returner = file_get_contents ( $cfile );
touch ( $cfile );
file_put_contents ( $cfile, strval($returner) );
$returner = file_get_contents ( $cfile );
return $returner;
} else {
$returner = "<li><span>Temp file not written</span></li>";
return $returner;
}
} else {
$reader->open($url);
$i = 0;
$k = 1;
while ($i < $num)
{
$j = 0;
while ($reader->read() && $j < 4) // run through each tweet
{
if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == $tags[$j])
{
while ($reader->read())
{
if ($reader->nodeType == XMLReader::TEXT && $j == 0)
{
if ($k) {
$tweets[$i][$local[$j]] = $reader->value;
$j++;
$k=0;}
else {$k=1;}
break;
}
else if ($reader->nodeType == XMLReader::TEXT)
{
$tweets[$i][$local[$j]] = $reader->value;
$j++;
break;
}
}
}
}
$i++;
}
$returner = "";
foreach ($tweets as $value) {
if ($value[user] != 'fugataquintet') {
$returner .= '<li class="retweet">';
} else {
$returner .= '<li>';
}
$messager = $value[msg];
$messager = " ".preg_replace( "/(([[:alnum:]]+:'/'/)|www'.)([^[:space:]]*)"."([[:alnum:]#?'/&=])/i", "<a href='"''1''3''4'" target='"_blank'">"."''1''3''4</a>", $messager);
$messager = preg_replace( "/ +@([a-z0-9_]*) ?/i", " <a href='"http://twitter.com/#!/''1'" target='"_blank'">@''1</a> ", $messager);
$messager = preg_replace( "/ +#([a-z0-9_]*) ?/i", " <a href='"http://twitter.com/search?q=%23''1'" target='"_blank'">#''1</a> ", $messager);
$returner .= '<span>'.$messager.'</span><a class="datereplace" href="http://twitter.com/#!/fugataquintet" title="'.$value[time].'">'.$value[time].'</a></li>';
}
touch ( $cfile );
file_put_contents ( $cfile, strval($returner) );
return $returner;
}
} else {
$returner = file_get_contents ( $cfile );
return $returner;
}
}
发布的代码受到处理文件系统的经典竞争条件的影响;OWASP有一个描述: https://www.owasp.org/index.php/File_Access_Race_Condition:_TOCTOU
当您在共享主机上时,其他人可能会定期清理系统临时目录。如果需要更永久的缓存,请尝试将文件保存在其他位置。
以下代码检查文件是否存在,如果不存在,则创建该文件,并使其保持打开状态。这可以防止文件被另一个进程(例如临时目录空)删除,直到函数退出。
<? //PHP 5.4+
function getTweets($num){
//This will keep the file open,
//so that the file cannot be deleted during when this function executes.
$file = new 'SplFileObject(
'sys_get_temp_dir() . '/e1z' . $type . 'sha1('something'),
'c+' //
);
if ($file->getSize() !== 0 &&
'time() - $file->getMTime() < 100)
{
$contents = '';
foreach($file as $line){
$contents .= $line;
}
return $contents;
}
//Get data from twitter
//Write it to $file
//return data from twitter
}
?>
你能试试这个简化版本的过期检查吗?
if(is_file($cfile) == false OR filemtime($cfile) < time() - 100)
{
// fetch here
}
else
{
// load from cache here
}
编辑:我还制作了一个削减版本,可以获取
function CacheTweetsXML($num)
{
$cfile = sys_get_temp_dir().'/e1z'. $type . md5 ( 'something' );
if(is_file($cfile) == false OR filemtime($cfile) < time() - 100)
{
// fetch here
$url = 'http://api.twitter.com/1/statuses/user_timeline.xml?screen_name=boriskourt&include_rts=true&count=' . $num;
if($xml = @file_get_contents($url) and @file_put_contents($cfile,$xml))
{
return $xml;
}
elseif(is_file($cfile)) // can't load, return from cache
{
return file_get_contents($cfile);
}
else // cant load and isn't cached, return false
{
return false;
}
}
else // load from cache here
{
return file_get_contents($cfile);
}
}
也不要忘记清理$type