1

私は自分自身が再利用するための簡単な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;    
    }
}
4

2 に答える 2

2

投稿されたコードは、ファイルシステムを処理するための古典的な競合状態に悩まされています。1つの説明は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
}
?>
于 2012-05-02T07:49:15.277 に答える
0

この簡略化されたバージョンの有効期限チェックを試していただけますか?

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をクリーンアップすることも忘れないでください

于 2012-05-02T05:44:52.853 に答える