PHP:显示Web服务中的图像

时间:2013-09-03 03:47:48

标签: php jquery ajax web-services

我正在使用外部网络服务,该服务将返回我将在我的网站上显示的图片网址,例如:

$url = get_from_web_service();
echo '<img url="'.$url.'" />';

一切正常,除非我有100张图片要显示,然后调用网络服务成为时间&amp;资源消耗。

//the problem
foreach($items as $item) {
   $url = get_from_web_service($item);
   echo '<img url="'.$url.'" />';
}

所以现在我正在考虑两种选择:

//Option1: Using php get_file_contents():
foreach($items as $item)
{
   echo '<img url="url_to_my_website/get_image.php?id='.$item->id.'" />'
}

get_image.php :

$url = get_from_web_service($id);
header("Content-Type: image/png");
echo file_get_contents($url);


//Option2: Using ajax:

echo '<img scr="dummy_image_or_website_logo" data-id="123" />';

//ajax call to the web service to get the id=123 and get the url then add the src attribute to that image.

THOUGHTS

  1. 第一个选项似乎更直接,但我的服务器可能是 超载并参与每一个图像请求。
  2. 第二个选项全部由浏览器&amp;网络服务所以我的服务器根本不参与。但对于每个图像,我正在进行2次调用1 ajax调用以获取图像URL,另一个调用以获取图像。所以加载时间可能会有所不同,并且ajax调用可能会因大量调用而失败。
  3. 信息

    1. 该页面将显示约50张图像。
    2. 此服务将在给定时间由大约100位用户使用。
    3. 我无法控制网络服务,所以我无法更改其功能,并且每次通话都不接受超过1张图片ID。
    4. 我的问题

      1. 我应该考虑哪些更好的选择?
      2. 如果没有,我应该遵循哪个选项?最重要的是为什么我应该遵循那个?
      3. 由于

9 个答案:

答案 0 :(得分:9)

方法1:在PHP中进行渲染

<强>优点:

  • 允许自定义标头独立于任何服务器软件。如果您正在使用通常不缓存的内容(例如带有查询字符串的PHP文件),或者将其添加到需要标题功能的软件包中,而不管服务器软件如何,这是一个非常好的主意。

  • 如果您知道如何使用GDImagick,则可以轻松调整图像的大小,裁剪,压缩,索引等,以减少图像文件的大小(有时会大幅减少)和使页面加载速度明显加快。

  • 如果将宽度和高度作为变量传递给PHP文件,则可以动态设置尺寸:

    <div id="gallery-images">
        <noscript>
            <!-- So that the thumbnail is small for old mobile devices //-->
            <img src="get-image.php?id=123&h=200&w=200" />
        </noscript>
    </div>
    <script type="text/javascript">
        /* Something to create an image element inside of the div.
         * In theory, the browser height and width can be pulled dynamically
         * on page load, which is useful for ensuring that images are no larger
         * than they need to be. Having a function to load the full image
         * if the borwser becomes bigger isn't a bad idea though.
         */
    </script>
    

    对于拥有图片库的网页上的移动用户,这将是非常体贴的。这也是带宽有限的用户非常考虑(就像阿拉斯加的几乎每个人一样。我从个人经验中说出这一点。)

  • 如果用户在网站上传图像,则可以轻松清除图像的EXIF数据。这对于用户隐私以及making sure there aren't any malicious scripts living in your JPGs非常重要。

  • 可以动态创建大型image sprite,并在导致延迟时大幅减少HTTP请求。这是一项很多的工作,所以这不是一个非常强大的专业人士,但你仍然可以使用这种方法,你不能使用第二种方法。

<强>缺点

  • 根据图像的数量和大小,这可能会给您的服务器带来很大压力。当与浏览器缓存一起使用时,动态图像将从缓存中提取而不是重新生成,但是机器人仍然可以很容易地为动态图像提供多次服务。

  • 它需要了解HTTP标头,基本的图像处理技巧,以及如何在PHP中使用图像处理库才能有效。

方法2:AJAX

<强>优点:

  • 页面将在任何图像之前完成加载。如果您的内容绝对需要尽快加载,并且图像不是很重要,这一点非常重要。

  • 与任何类型的动态PHP解决方案相比,实现起来要简单,容易且快得多。

  • 它将HTTP请求分开,因此初始内容加载速度更快(因为可以根据浏览器操作而不仅仅是页面加载来发送HTTP请求)。

<强>缺点:

  • 它不会减少HTTP请求的数量,只是将它们分开。另请注意,除了所有这些图像之外,还将至少有一个额外的外部JS文件。

  • 如果终端设备(例如较旧的移动设备)不支持JavaScript,则不显示任何内容。解决这个问题的唯一方法是让所有图像在一些<noscript>标记之间正常加载,这需要PHP生成两倍的HTML。

  • 要求您在页面中添加loading.gif(以及其他HTTP请求)或Please wait while these images load文字。我个人认为这对网站用户来说很烦人,因为我希望在页面“完成加载”时看到所有内容。

结论:

如果您具备学习如何有效使用方法1的背景知识或时间,那么它提供了更大的潜力,因为它允许在加载后处理页面发送的图像和HTTP请求。

相反,如果您正在寻找一种简单的方法来隔离您的HTTP请求,或者想要通过稍后加载额外的图像来加快内容加载,那么方法2就是您的答案。

回顾方法1和方法2,看起来将两种方法结合使用可能是最好的答案。将两个缓存和压缩的图像与页面一起加载(一个是可见的,另一个是缓冲区,这样用户每次点击“下一个”时都不必等待),并且其余的一个一个地加载一个用户认为合适。

在您的具体情况下,如果您的图片可以以“幻灯片”方式显示,我认为方法2最有效。如果需要立即加载所有图片,尝试压缩它们并使用方法1应用浏览器缓存。如果页面加载上的图像请求太多正在破坏您的速度,请尝试图像spriting。

答案 1 :(得分:3)

截至目前,您正在联系网络服务100次。您应该更改它,使其仅与一次联系网络服务,并检索所有100个图像的数组,而不是分别检索每个图像。

然后你可以遍历这个数组,这将非常快,因为不需要进一步的webtransactions。

答案 2 :(得分:2)

如果您从网络服务获取的图像本质上不是动态的,即不经常更改/修改,我建议在您的服务器上设置一个预定的进程/ cron作业,该作业从Web服务获取图像并在本地存储(在您的服务器本身中),因此您只能从服务器在网页上显示图像,并且每次向最终用户提供网页时都要避免第三方服务器往返。

答案 3 :(得分:1)

两个选项都无法解决您的问题,可能会让情况变得更糟。

对于选项1:

费用最多的时间是&#34; get_from_web_service($item)&#34;,而代码只能由另一个脚本执行(如果文件&#34; get_image.php& #34;在同一服务器上执行。)

对于选项2:

它只会使&#34; get-image-resource-request&#34;被浏览器触发,但您的服务器还需要处理&#34; get_from_web_service($item)&#34;。

有一点必须明确的是,问题是关于get_from_web_service的性能,最直接的建议是让它具有更好的性能。另一方面,我们可以减少并发连接的数量。我没有想到这一点,只有2个建议:

  1. 异步:用户没有浏览整个页面,他们只会注意到顶部的页面。如果您提到的图像并未全部显示在顶部,您可以使用jquery.lazyload扩展,它可以使图像资源在不可见区域不会请求服务器,直到它们可见。

  2. CSS Sprites :图像精灵是放入单个图像的图像集合。如果页面上的图像不会改变频率,您可以编写一些代码以便每天合并它们。

  3. 缓存图片:您可以将图像缓存在服务器或其他服务器上(更好)。并执行一些key-&gt;值工作:key是关于$ item,value是资源目录(url)。

  4. 我不是母语为英语的人,希望我能说清楚并对你有帮助。

答案 4 :(得分:0)

我不是专家,但我想每当你回声,它需要时间。得到100张图片不应该是一个问题(单独)

另外。也许get_from_web_service($item);应该可以拿一个数组?

$counter = 1;
$urls = array();
foreach($items as $item)
{
   $urls[$counter] = get_from_web_service($item);
   $counter++;
}
// and then you can echo the information?
foreach($urls as $url)
{
   //echo each or use a function to better do it
    //echo '<img url="url_to_my_website/get_image?id='.$url->id.'" />'

}

get_image.php :

$url = get_from_web_service($item);
header("Content-Type: image/png");
echo file_get_contents($url);

最后,如果你能打电话

那将是非常好的
get_from_web_service($itemArray); //intake the array and return images 

答案 5 :(得分:0)

选项3: 将请求缓存到Web服务

答案 6 :(得分:0)

选项一是最佳选择。我还想确保图像缓存在服务器上,以便原始Web服务器不需要多次往返同一图像。

如果您感兴趣,这是我用于缓存图像等的代码的核心(注意,有一些东西,比如将相同的内容保留回客户端等):

<?php
function error404() {
    header("HTTP/1.0 404 Not Found");
    echo "Page not found.";
    exit;
}

function hexString($md5, $hashLevels=3) {
    $hexString = substr($md5, 0, $hashLevels );
    $folder = "";

    while (strlen($hexString) > 0) {
        $folder =  "$hexString/$folder";
        $hexString = substr($hexString, 0, -1);
    }

    if (!file_exists('cache/' . $folder))
        mkdir('cache/' . $folder, 0777, true);

    return 'cache/' . $folder . $md5;
}

if (!isset($_GET['img']))
    error404();

getFile($_GET['img']);

function getFile($url) {
    // true to enable caching, false to delete cache if already cached
    $cache = true;

    $defaults = array(
        CURLOPT_HEADER => FALSE,
        CURLOPT_RETURNTRANSFER => 1,
        CURLOPT_FOLLOWLOCATION => 1,
        CURLOPT_MAXCONNECTS => 15,
        CURLOPT_CONNECTTIMEOUT => 30,
        CURLOPT_TIMEOUT => 360,
        CURLOPT_USERAGENT => 'Image Download'
    );

    $ch = curl_init();
    curl_setopt_array($ch, $defaults);
    curl_setopt($ch, CURLOPT_URL, $_GET['img']);

    $key  = hexString(sha1($url));
    if ($cache && file_exists($key)) {
        return file_get_contents($key);
    } elseif (!$cache && file_exists($key)) {
        unlink($key);
    }

    $data = curl_exec($this->_ch);
    $info = curl_getinfo($this->_ch);

    if ($cache === true && $info['http_code'] == 200 && strlen($data) > 20)
        file_put_contents($key, $data);
    elseif ($info['http_code'] != 200)
        error404();

    return $data;
}

$content = getURL($_GET['img']);
if ($content !== null or $content !== false) {
    // Success!
    header("Content-Type: image");
    echo $content;
}

答案 7 :(得分:0)

这两个选项都不会解决服务器资源使用问题。不过,我会建议选项1.第二个会延迟页面加载,导致网站速度变慢,并降低您的搜索引擎优化评级。

最适合您的选择是:

foreach($items as $item) {
    echo '<img url="url_to_my_website/get_image.php?id='.$item->id.'" />'
}

然后神奇发生的地方是 get_image.php

if(file_exists('/path_to_local_storage/image_'.$id.'.png')) {
    $url = '/path_to_images_webfolder/image_'.$id.'.png';
    $img = file_get_contents($url);
} else {
    $url = get_from_web_service($id);
    $img = file_get_contents($url);
    $imgname = end(explode('/', $url));
    file_put_contents($imgname, $img);
}

header("Content-Type: image/png");
echo $img;

这是每个图像只运行一次Web服务请求,然后将其存储在本地空间。下次请求图像时 - 您将从本地空间提供图像,跳过对Web服务的请求。

当然,将图像ID视为唯一且持久的。

可能不是最好的解决方案,但应该对你有用。

答案 8 :(得分:0)

正如我们在上面看到的那样,您在<img>标记src属性中包含了网络服务提供图片的网址,可以安全地假设这些网址不是机密或机密的。< / p>

知道上述情况,get_image.php中的以下代码段将以最小的开销工作:

$url = get_from_web_service($id);
header("Location: $url");

如果您从给定的客户端收到大量后续请求id,则可以通过利用浏览器的内部缓存来减少请求数量。

header("Cache-Control: private, max-age=$seconds");
header("Expires: ".gmdate('r', time()+$seconds));

通过Memcached,数据库或普通文件来实现服务器端缓存:

is_dir('cache') or mkdir('cache');
$cachedDataFile = "cache/$id";
$cacheExpiryDelay = 3600; // an hour

if (is_file($cachedDataFile) && filesize($cachedDataFile) 
     && filemtime($cachedDataFile) + $cacheExpiryDelay > time()) {
    $url = file_get_contents($cachedDataFile);
} else {
    $url = get_from_web_service($id);
    file_put_contents($cachedDataFile, $url,  LOCK_EX);
}

header("Cache-Control: private, max-age=$cacheExpiryDelay");
header("Expires: ".gmdate('r', time() + $cacheExpiryDelay));
header("Location: $url");