如何修复运行速度缓慢的PHP代码


How to fix PHP code running painfully slow?

这是我的代码

$facebook_from_file = file_get_contents('path/to/file');
$facebookfiles = explode(',', $facebook_from_file);
for($i = 1; $i <= 2; $i++) {
    $facebookfile = array_rand($facebookfiles);
    $filename = "http://sitename.com/".$facebookfiles[$facebookfile];
    outputtags($filename);
}

类似的代码执行8次,从不同的目录中随机获取网页。此代码需要8秒才能执行。这个代码有问题吗?我想我应该提到我正在使用iPage共享主机。iPage服务器速度慢吗?

这是outputtags() 的代码

function outputtags($filename, $other, $programming)
{
  $html = file_get_contents_curl($filename);
  $doc = new DOMDocument();
  @$doc->loadHTML($html);
  $nodes = $doc->getElementsByTagName('title');
  $title = $nodes->item(0)->nodeValue;
  $metas = $doc->getElementsByTagName('meta');
  for ($i = 0; $i < $metas->length; $i++) {
    $meta = $metas->item($i);
    if ($meta->getAttribute('property') == 'og:title')
      $ogtitle = $meta->getAttribute('content');
    if ($meta->getAttribute('property') == 'og:image')
      $ogimage = $meta->getAttribute('content');
    if ($other) {
      if ($meta->getAttribute('property') == 'og:description')
        $ogdescription = $meta->getAttribute('content');
    }
  }
  echo '<p style="margin:0;"><a href=' . $filename . ' target=_blank>' . $ogtitle . '</a></p>';
  if (!$other)
    echo '<a href=' . $filename . ' target=_blank><img style="margin:0 0 40px 0;" src="' . $ogimage . '" alt=""></a></br>';
  if ($other) {
    if (!$programming)
      echo '<a href=' . $filename . ' target=_blank><img src="' . $ogimage . '" alt=""></a></br>';
    echo '<p style="margin:0 0 40px 0;">' . $ogdescription . '</p>';
  }
}

这是file_get_contents_curl()

function file_get_contents_curl($url)
{
  $ch = curl_init();
  curl_setopt($ch, CURLOPT_HEADER, 0);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
  $data = curl_exec($ch);
  curl_close($ch);
  return $data;
}

我不能代表您的网络主机发言,但共享主机通常不太好。您正在与其他用户/客户"共享"服务器的所有资源。这就是CPU、RAM和带宽。

所有主机都会过度销售,并且某些主机会过度拥挤服务器。也就是说,8秒内8个网页听起来并没有那么糟糕。

切换到带宽不受控制的VPS可能会有所帮助,尽管这取决于你正在抓取的网站是否有足够的带宽(问题可能在另一端)。

如果您在家或工作中有快速宽带连接,请尝试安装Apache或XAMPP并在本地测试您的脚本。如果速度很快,你的主人就是问题所在。

另一点值得记住的是,如果你向目标网站发送请求,目标网站可能会限制你的连接。

如果他们不需要实际的请求属性,那么您可能可以使用include来提取内容:

// you would add this function and then replace your call 
// to file_get_contents_curl() with it
function file_get_contents_php($filename) {
    ob_start();
    include($filename);
    return ob_get_clean();
}

如果它们确实依赖于请求属性,或者可能会影响试图加载它们的页面上的某些内容,那么这可能不是一个好主意。

最理想的解决方案是,由于这只是元内容,将其存储在数据库或配置文件中,您可以从任何地方加载,而不会产生什么后果。您可能有一个名为metas.json:的文件

{
   "/facebook/file/url_1.php": {
       "title": "Url 1",
       "og": {
           "title": "Url 1",
           "description": "This is the og:description for url_1.php",
           "image": "http://somesite.com/path/to/url1/image.jpg"
       }
   },
   "/facebook/file/url_2.php": {
       "title": "Url 2",
       "og": {
           "title": "Url 2",
           "description": "This is the og:description for url_2.php",
           "image": "http://somesite.com/path/to/url2/image.jpg"
       }
   },
   "/facebook/file/url_3.php": {
       "title": "Url 3",
       "og": {
           "title": "Url 3",
           "description": "This is the og:description for url_3.php",
           "image": "http://somesite.com/path/to/url3/image.jpg"
       }
   },
   "/facebook/file/url_4.php": {
       "title": "Url 4",
       "og": {
           "title": "Url 4",
           "description": "This is the og:description for url_4.php",
           "image": "http://somesite.com/path/to/url4/image.jpg"
       }
   }
}

在这些页面中,您可以简单地创建这样一个函数:

/**
 * Get a hash of meta tags for a page URI
 *
 * Returns an associative array of tags and values or false
 * if the URI is not present in configuration.
 *
 * @param String $uri    The URI of the page
 * @return Array|Boolean
 */
function get_metas($uri) {
    $json = file_get_contents('/path/to/metas.json');
    $metas = json_decode($json, true);
    
    return $metas && isset($metas[$uri]) 
        ? $metas[$uri]
        : false;
}
/**
 * Includes meta tags for a URI
 *
 * @param String $uri    The URI of the page
 * @return void
 */    
function include_meta_tags($uri) {
    if (false !== ($metas = get_meta_tags($uri))) {
        echo $metas;
    }
}
/**
 * Gets an HTML string of meta tags for a URI
 *
 * @param String $uri  The URI of the page
 * @return String|Boolean
 */
function get_meta_tags($uri) {
    $metas = get_metas($uri);
  
    if (!$metas) {
       return false;
    }
    $tags = array();
    if (isset($metas['title'])) {
        $tags[] = sprintf('<title>%s</title>', $metas['title']);
    }
    if (isset($metas['og']) {
       foreach ($metas['og'] as $property => $value) {
           $tags[] = sprintf('<meta property="og:%s" content="%s">', $property, $value);
       }
    }
    return impolde("'n", $tags);
}

因此,在你所有页面的头部,你可以做:

<?php echo include_meta_tags($_SERVER['REQUEST_URI']); ?>

然后你的输出函数会看起来像:

function outputtags($uri, $other = null, $programming = null) {
    $metas = get_metas($uri);
    $ogtitle = isset($metas['og']['title'])
         ? $metas['og']['title']
         : $metas['title'];
    $ogdescription = isset($metas['og']['description'])
         ? $metas['og']['description']
         : $metas['title'];
    
    $ogimage = isset($metas['og']['image'])
         ? $metas['og']['image']
         : '';
    // now your existing logic for outputting the markup
    printf(
        '<p style="margin:0;"><a href="%s" target="_blank">%s</a></p>'
        $uri,
        $ogtitle
    );
    if (!$other) {
        printf(
           '<a href="%s" target="_blank"><img style="margin:0 0 40px 0;" src="%s" alt="" /></a><br />'
           $uri,
           $ogimage
        );
    } else {
      if (!$programming) {
          printf(
              '<a href="%s" target=_blank><img src="%s" alt="" /></a></br>',
              $uri,
              $ogimage
          );
          printf('<p style="margin:0 0 40px 0;">%s</p>', $ogdescription);
      }
    }
  
}

outputtags()$filename 中的url中提取元标签

很可能是你的问题。这与用网络浏览器点击URL本质上是一样的——你必须等待其他网络服务器像往常一样提供文件,因此响应时间会有很大的变化,提供页面所需的总时间将至少是访问这8个远程URL所需的时间。

如果你真的需要这样做,你可以使用cURL,这样你就可以控制超时等等,但总的来说,你仍然会受制于其他服务器的响应时间。

更新

但这两个文件都在同一个域上。我能做些什么吗?

是的,执行代码的网页与提取$filename的网页相同。

那么是的。通过文件系统而不是url访问它们。我不知道outputtags在内部做什么,但我认为您在内部使用file_get_contents

因此,与其提供URL,不如提供文件路径。看起来你从中获得元标签的文件都是从你网站的文档根目录中列出的,所以这可能很容易:

for($i=1;$i<=2;$i++){
    $facebookfile = array_rand($facebookfiles);
    // filename is now something like
    // /var/www/site.com/the_face_book_file.html
    $filename = $_SERVER['DOCUMENT_ROOT'] . DIRECTORY_SEPARATOR . $facebookfiles[$facebookfile];
    outputtags($filename);
}

当然,如果这些是需要处理的.php文件,那么您可能会运气不佳,这取决于它们的工作方式。