使用PHP脚本提供图像与直接加载图像

使用PHP脚本提供图像与直接加载图像,php,Php,我想监控加载一些外部图像的频率。 因此,我的想法不是像这样直接给出uri: www.site.com/image1.jpg <img src="www.site.com/serveImage.php?img=image1.jpg"> $image=imagecreatefromjpeg($_GET['img']); imagejpeg($image); header('Content-type: image/jpeg'); passthru('cat /path/to/imag

我想监控加载一些外部图像的频率。 因此,我的想法不是像这样直接给出uri:

www.site.com/image1.jpg
<img src="www.site.com/serveImage.php?img=image1.jpg">
$image=imagecreatefromjpeg($_GET['img']);
imagejpeg($image);
header('Content-type: image/jpeg');
passthru('cat /path/to/image/file.jpg');
<?php
$filepath=$_SERVER['REQUEST_URI'];
$filepath='.'.$filepath;
if (file_exists($filepath))
{
touch($filepath,filemtime($filepath),time()); // this will just record the time of access in file inode. you can write your own code to do whatever
$path_parts=pathinfo($filepath);
switch(strtolower($path_parts['extension']))
{
case "gif":
header("Content-type: image/gif");
break;
case "jpg":
case "jpeg":
header("Content-type: image/jpeg");
break;
case "png":
header("Content-type: image/png");
break;
case "bmp":
header("Content-type: image/bmp");
break;
}
header("Accept-Ranges: bytes");
header('Content-Length: ' . filesize($filepath));
header("Last-Modified: Fri, 03 Mar 2004 06:32:31 GMT");
readfile($filepath);

}
else
{
 header( "HTTP/1.0 404 Not Found");
 header("Content-type: image/jpeg");
 header('Content-Length: ' . filesize("404_files.jpg"));
 header("Accept-Ranges: bytes");
 header("Last-Modified: Fri, 03 Mar 2004 06:32:31 GMT");
 readfile("404_files.jpg");
}
/*
By Samer Mhana
www.dorar-aliraq.net
*/
?>
我可以创建一个读取图像的PHP脚本,因此我构建了一个PHP文件,我的HTML如下所示:

www.site.com/image1.jpg
<img src="www.site.com/serveImage.php?img=image1.jpg">
$image=imagecreatefromjpeg($_GET['img']);
imagejpeg($image);
header('Content-type: image/jpeg');
passthru('cat /path/to/image/file.jpg');
<?php
$filepath=$_SERVER['REQUEST_URI'];
$filepath='.'.$filepath;
if (file_exists($filepath))
{
touch($filepath,filemtime($filepath),time()); // this will just record the time of access in file inode. you can write your own code to do whatever
$path_parts=pathinfo($filepath);
switch(strtolower($path_parts['extension']))
{
case "gif":
header("Content-type: image/gif");
break;
case "jpg":
case "jpeg":
header("Content-type: image/jpeg");
break;
case "png":
header("Content-type: image/png");
break;
case "bmp":
header("Content-type: image/bmp");
break;
}
header("Accept-Ranges: bytes");
header('Content-Length: ' . filesize($filepath));
header("Last-Modified: Fri, 03 Mar 2004 06:32:31 GMT");
readfile($filepath);

}
else
{
 header( "HTTP/1.0 404 Not Found");
 header("Content-type: image/jpeg");
 header('Content-Length: ' . filesize("404_files.jpg"));
 header("Accept-Ranges: bytes");
 header("Last-Modified: Fri, 03 Mar 2004 06:32:31 GMT");
 readfile("404_files.jpg");
}
/*
By Samer Mhana
www.dorar-aliraq.net
*/
?>

但我不知道如何从磁盘读取图像并返回它。我是返回字节数组还是设置内容类型

亲切问候,,
米歇尔

您必须设置内容类型:

header("Content-type: image/jpeg");
然后加载图像并按如下方式输出:

www.site.com/image1.jpg
<img src="www.site.com/serveImage.php?img=image1.jpg">
$image=imagecreatefromjpeg($_GET['img']);
imagejpeg($image);
header('Content-type: image/jpeg');
passthru('cat /path/to/image/file.jpg');
<?php
$filepath=$_SERVER['REQUEST_URI'];
$filepath='.'.$filepath;
if (file_exists($filepath))
{
touch($filepath,filemtime($filepath),time()); // this will just record the time of access in file inode. you can write your own code to do whatever
$path_parts=pathinfo($filepath);
switch(strtolower($path_parts['extension']))
{
case "gif":
header("Content-type: image/gif");
break;
case "jpg":
case "jpeg":
header("Content-type: image/jpeg");
break;
case "png":
header("Content-type: image/png");
break;
case "bmp":
header("Content-type: image/bmp");
break;
}
header("Accept-Ranges: bytes");
header('Content-Length: ' . filesize($filepath));
header("Last-Modified: Fri, 03 Mar 2004 06:32:31 GMT");
readfile($filepath);

}
else
{
 header( "HTTP/1.0 404 Not Found");
 header("Content-type: image/jpeg");
 header('Content-Length: ' . filesize("404_files.jpg"));
 header("Accept-Ranges: bytes");
 header("Last-Modified: Fri, 03 Mar 2004 06:32:31 GMT");
 readfile("404_files.jpg");
}
/*
By Samer Mhana
www.dorar-aliraq.net
*/
?>

要实现类似的效果,您的脚本需要:

  • 发送正确的标题,这取决于图像的类型:image/gif、image/png、image/jpeg等等
  • 发送图像的数据
  • 确保未发送任何其他内容(无空白,无任何内容)
这是通过函数完成的,一些代码如下:

header("Content-type: image/gif");

或者随便什么,取决于图像的类型


要发送图像数据,您可以使用以下功能:

读取文件并将其写入 输出缓冲区

这样,在一个函数中,您可以读取文件并输出其内容


作为旁注:

  • 您必须设置一些安全措施,以确保用户不能通过您的脚本请求任何他们想要的内容:您必须确保它只提供来自您期望的目录的图像;例如,像
    serveImage.php?file=/etc/passwd
    这样的文件都不应该是正确的
  • 如果您只想获得每天加载文件的次数,解析Apache的日志文件可能是一个好主意(例如,通过cron每天00:05运行的批处理来解析前一天的日志);您不会有实时统计信息,但它需要较少的服务器资源(没有PHP提供静态文件)

您最好检查一下服务器访问日志。通过php运行所有图像可能会给您的服务器带来一点负载。

通过脚本发送图像对于其他事情(如按需调整大小和缓存)很好

正如Pascal MARTIN所回答的,函数
readfile
,这些标题是要求:

  • 内容类型
    • 此内容的mime类型
    • 示例:
      标题('Content-Type:image/gif')
    • 查看函数
    • 类型
      • image/gif
      • image/jpeg
      • image/png
但除了明显的内容类型之外,您还应该查看其他标题,例如:

  • 内容长度
    • 响应正文的长度(八位字节)
    • 示例:
      标题('Content-Length:348')
    • 查看函数
    • 允许更好地使用连接
  • 最后修改
    • 请求对象的上次修改日期,RFC 2822格式
    • 示例:
      header('Last-Modified:Tue,1994年11月15日12:45:26 GMT')
    • 请参阅函数并将其格式化为所需的RFC 2822格式
      • 示例:
        header('Last-Modified:').date(日期\u RFC2822,filemtime($filename))
    • 如果文件修改时间相同,则可以在发送304后退出脚本
  • 状态码
    • 示例:
      标题(“HTTP/1.1 304未修改”)
    • 您现在可以退出,不再发送图像
有关上次修改的时间,请在
$\u服务器中查找此时间

  • 如果修改自
    • 如果内容不变,则允许返回未修改的内容
    • 示例:
      如果修改自:Sat,1994年10月29日19:43:31 GMT
    • 如果自

另外,当用户RMC在图像上并选择“另存为”时,如果希望用户看到真实的文件名而不是脚本名,则还需要设置此标题:

header('Content-Disposition: filename=$filename');
我使用“passthru”函数调用“cat”命令,如下所示:

www.site.com/image1.jpg
<img src="www.site.com/serveImage.php?img=image1.jpg">
$image=imagecreatefromjpeg($_GET['img']);
imagejpeg($image);
header('Content-type: image/jpeg');
passthru('cat /path/to/image/file.jpg');
<?php
$filepath=$_SERVER['REQUEST_URI'];
$filepath='.'.$filepath;
if (file_exists($filepath))
{
touch($filepath,filemtime($filepath),time()); // this will just record the time of access in file inode. you can write your own code to do whatever
$path_parts=pathinfo($filepath);
switch(strtolower($path_parts['extension']))
{
case "gif":
header("Content-type: image/gif");
break;
case "jpg":
case "jpeg":
header("Content-type: image/jpeg");
break;
case "png":
header("Content-type: image/png");
break;
case "bmp":
header("Content-type: image/bmp");
break;
}
header("Accept-Ranges: bytes");
header('Content-Length: ' . filesize($filepath));
header("Last-Modified: Fri, 03 Mar 2004 06:32:31 GMT");
readfile($filepath);

}
else
{
 header( "HTTP/1.0 404 Not Found");
 header("Content-type: image/jpeg");
 header('Content-Length: ' . filesize("404_files.jpg"));
 header("Accept-Ranges: bytes");
 header("Last-Modified: Fri, 03 Mar 2004 06:32:31 GMT");
 readfile("404_files.jpg");
}
/*
By Samer Mhana
www.dorar-aliraq.net
*/
?>

在Linux上工作。节省资源。

您可以在Apache配置或
.htaccess
中添加一行代码,将目录中的所有图像请求重写为php脚本,而不是更改HTML中的直接图像url。然后,在该脚本中,您可以使用请求头和
$\u服务器
数组来处理请求并提供文件

首先在.htaccess中:

RewriteRule ^(.*)\.jpg$ serve.php [NC]
RewriteRule ^(.*)\.jpeg$ serve.php [NC]
RewriteRule ^(.*)\.png$ serve.php [NC]
RewriteRule ^(.*)\.gif$ serve.php [NC]
RewriteRule ^(.*)\.bmp$ serve.php [NC]
脚本
service.php
必须与
.htaccess
位于同一目录中。您可能会这样写:

www.site.com/image1.jpg
<img src="www.site.com/serveImage.php?img=image1.jpg">
$image=imagecreatefromjpeg($_GET['img']);
imagejpeg($image);
header('Content-type: image/jpeg');
passthru('cat /path/to/image/file.jpg');
<?php
$filepath=$_SERVER['REQUEST_URI'];
$filepath='.'.$filepath;
if (file_exists($filepath))
{
touch($filepath,filemtime($filepath),time()); // this will just record the time of access in file inode. you can write your own code to do whatever
$path_parts=pathinfo($filepath);
switch(strtolower($path_parts['extension']))
{
case "gif":
header("Content-type: image/gif");
break;
case "jpg":
case "jpeg":
header("Content-type: image/jpeg");
break;
case "png":
header("Content-type: image/png");
break;
case "bmp":
header("Content-type: image/bmp");
break;
}
header("Accept-Ranges: bytes");
header('Content-Length: ' . filesize($filepath));
header("Last-Modified: Fri, 03 Mar 2004 06:32:31 GMT");
readfile($filepath);

}
else
{
 header( "HTTP/1.0 404 Not Found");
 header("Content-type: image/jpeg");
 header('Content-Length: ' . filesize("404_files.jpg"));
 header("Accept-Ranges: bytes");
 header("Last-Modified: Fri, 03 Mar 2004 06:32:31 GMT");
 readfile("404_files.jpg");
}
/*
By Samer Mhana
www.dorar-aliraq.net
*/
?>


(这个脚本可以改进!)

我也使用readfile为我的图像提供服务,但为了安全性和额外功能,我已经付出了额外的努力

我建立了一个数据库,它存储图像id、尺寸和文件扩展名。这也意味着图像需要上传(允许可选的大小调整),所以我只对内容使用系统,而不是网站本身所需的图像(如背景或精灵)

它还能很好地确保您只能请求图像

因此,为简化的工作流程提供服务的方式如下(此处无法发布生产代码):

1) 获取请求的映像的ID

2) 在数据库中查找

3) 基于扩展名抛出标题(“jpg”在上传时被重新映射为“jpeg”)

4)
readfile(“/images/$id.$extension”)


5) 或者,保护/images/dir,使其不能被索引(在我自己的系统中,这不是一个问题,因为它将像/image/view/11这样的URL映射到像/index.php?module=image&action=view&id=11这样的东西)

hmm,这肯定会奏效。当负载出现问题时,我会保存它。此外,通过PHP脚本运行它们会影响客户端缓存,这实际上会增加读取负载。@rob:这与运行无关