底部的新问题
我想编写一个PHP脚本,可以发送附加到电子邮件的给定URL的内容,而无需下载和上传。
我的资源有限:正常托管帐户 PHP 和 64M内存限制和 ~1GB存储空间
我的第一个代码是带有fopen()
的简单sendmail,但如果给定的文件太大,则会出现内存问题。我该如何解决这个问题?
<?php
// return the file size of remote file
function ffilesize($remoteFile,$verbose=0){
$ch = curl_init($remoteFile);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //not necessary unless the file redirects (like the PHP example we're using here)
$data = curl_exec($ch);
curl_close($ch);
if ($data === false) {
echo 'cURL failed';
exit;
}
$contentLength = 'unknown';
$status = 'unknown';
if (preg_match('/^HTTP\/1\.[01] (\d\d\d)/', $data, $matches)) {
$status = (int)$matches[1];
}
if (preg_match('/Content-Length: (\d+)/', $data, $matches)) {
$contentLength = (int)$matches[1];
}
return ($verbose)?number_format($contentLength)." bytes":$contentLength;
}
$file_url=$_GET['q']; // the given URL
print ffilesize($file_url,1); // check the file size of given URL
if ($_GET['m']) { // allow to send mail
$filesize=ffilesize($file_url);
$to=$_GET['to']; // For the file to be sent.
$from="no-reply@domain.com"; // For the from line on the received email
$name=$_GET['fname']; // virtual name of attached file
$type="application/x-gzip";
$subject = "subj";
$mime_boundary = "==Multipart_Boundary_x".md5(mt_rand())."x";
// open the file for a binary read
$file = file_get_contents($file_url);
// read the file content into a variable
$data = chunk_split(base64_encode(file_get_contents($file_url)));
// now we encode it and split it into acceptable length lines
//ALREADY DONE, MOVE UP A FEW LINES
// message body
$message = "file attached";
// build headers
$headers = "Content-Type: multipart/mixed;\r\n" .
" boundary=\"{$mime_boundary}\"";
// put message body in mime boundries
$message = "This is a multi-part message in MIME format.\n\n" .
"--{$mime_boundary}\n" .
"Content-Type: text/plain; charset=\"iso-8859-1\"\n" .
"Content-Transfer-Encoding: 7bit\n\n" .
$message . "\n\n";
// attachment with mime babble
$message .= "--{$mime_boundary}\n" .
"Content-Type: {$type};\n" .
" name=\"{$name}\"\n" .
//"Content-Disposition: attachment;\n" .
//" filename=\"{$backfile}\"\n" .
"Content-Transfer-Encoding: base64\n\n" .
$data . "\n\n" .
"--{$mime_boundary}--\n";
// send mail
mail($to, $subject, $message, $headers);
}
?>
这种方法的问题:
73,214,655字节 致命错误:第58行/url2mail.php中允许的内存大小为67108864字节(尝试分配66846720字节) 第58行是:
$file = file_get_contents($file_url);
UPDATE 下面粘贴的工作版本,但仍受限于最大允许内存。我喜欢在内存中创建 Base 64编码片,而不是将文件下载到服务器。
<html><head><title></title>
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
</head><body bgcolor="#000000" color="#00ff00" style="padding: 3em;margin: 0;color: #00ff00;">
<pre><?php
if(preg_match("/ ***my top secret user agent string*** /i",$_SERVER['HTTP_USER_AGENT'])){
// security check
$mem=($_GET['M'])?$_GET['M']:'32M'; // change memory limit if needed
ini_set('memory_limit', $mem);
function ffilesize($remoteFile,$verbose=0){ // return the file size of remote file
$ch = curl_init($remoteFile);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); //not necessary unless the file redirects (like the PHP example we're using here)
$data = curl_exec($ch);
curl_close($ch);
if ($data === false) {
echo 'cURL failed';
exit;
}
$contentLength = 'unknown';
$status = 'unknown';
if (preg_match('/^HTTP\/1\.[01] (\d\d\d)/', $data, $matches)) {
$status = (int)$matches[1];
}
if (preg_match('/Content-Length: (\d+)/', $data, $matches)) {
$contentLength = (int)$matches[1];
}
return ($verbose)?number_format($contentLength)." bytes":$contentLength;
}
$furl=$_GET['q']; // the given URL
$fname=pathinfo(parse_url($furl, PHP_URL_PATH), PATHINFO_BASENAME); // name of given file
function return_bytes($val) { // convert size to bytes
$val = trim($val);
$last = strtolower($val[strlen($val)-1]);
switch($last) {
// The 'G' modifier is available since PHP 5.1.0
case 'g':
$val *= 1024;
case 'm':
$val *= 1024;
case 'k':
$val *= 1024;
}
return $val;
}
function mem($c=FALSE){ // checking allowed memory and used memory
$limit=return_bytes(ini_get('memory_limit'));
if ($c) {
return $limit - (memory_get_usage()*$c);
} else {
return $limit - memory_get_usage();
}
}
$filesize=(file_exists($fname))?filesize($furl):ffilesize($furl);
echo "<br /> file: ".number_format($filesize); // debug formatted file size
echo "<br /> mfree: ".number_format(mem()); // debug free memory
echo "<br /> mopt: ".number_format(mem(6)); // debug optimal memory usage
if($filesize>(mem())){ // debug file size information
echo "<br /> [".$filesize."] too large <br />";
} else {
echo "<br /> [".$filesize."] is cool <br />";
}
if ($_GET['to']) { // allow to send email
if (function_exists('curl_init')&&!file_exists($fname)) { // downloading the file
$ch = curl_init($furl);
$fh = fopen($fname, "w");
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.5) Gecko/20041107 Firefox/1.0');
curl_setopt($ch, CURLOPT_FILE, $fh);
curl_exec($ch);
curl_close($ch);
} else {
echo 'file existing on server';
}
$furl = $fname; // redeclare the $furl to local
$to=$_GET['to']."@gmail.com"; // For the file to be sent.
$from="no-reply@".$_SERVER['SERVER_NAME']; // For the from line on the received email
$name="asd.gif"; // virtual name .gif for content protection
$type="application/x-gzip";
$subject = "subj";
$mime_boundary = "==Multipart_Boundary_x".md5($rand)."x";
// open the file for a binary read
$file = fopen($furl,'rb');
// read the file content into a variable and encode it and split it into acceptable length lines
$data = chunk_split(base64_encode(fread($file,$filesize)));
// message body
$message = $furl." (".number_format(filesize($furl)).")";
// build headers
$headers = "Content-Type: multipart/mixed;\r\n" .
" boundary=\"{$mime_boundary}\"";
// put message body in mime boundries
$message = "This is a multi-part message in MIME format.\n\n" .
"--{$mime_boundary}\n" .
"Content-Type: text/plain; charset=\"iso-8859-1\"\n" .
"Content-Transfer-Encoding: 7bit\n\n" .
$message . "\n\n";
// attachment with mime babble
$message .= "--{$mime_boundary}\n" .
"Content-Type: {$type};\n" .
" name=\"{$name}\"\n" .
"Content-Transfer-Encoding: base64\n\n" .
$data . "\n\n" .
"--{$mime_boundary}--\n";
// close the file
fclose($file);
// send mail
if (mail($to, $subject, $message, $headers)) {
echo " done";
unlink($furl);
} else {
echo $furl;
}
}
} else {
echo "unauthorized request";
}
?></body></html>
所以,我的问题是:如何将给定文件(按URL)拆分为内存限制允许的切片?
例如: 32M 内存限制允许我在内存中存储 ~30M ,因此我应该将 30M 文件拆分为3部分。
答案 0 :(得分:1)
此功能可以完成任务:
function mail_page_contents( $url = '' )
{
if( $url && ( $contents = file_get_contents( $url ) ) )
{
$emailto = 'receiver@email.com';
$subject = 'Webpage Contents';
mail( $emailto , $subject , $contents );
}
}
答案 1 :(得分:0)
我会做这些步骤:
1) a) Store url-s in a `mysql` table
b) if you does not have mysql than store the urls in a `csv` file.
2) - Php reads the urls
a) from the table (with `mysqli` php lib)
b) with `fgetcsv` function
- and dowload the content of the url with `curl`
- zip the content with `ZipArchive` class. /if you want to use less space and bandwith/
- Send the zipped content as attached file with `PHPMailer`
3) The 2) should run over the urls (and somehow flag what url-s are examined)
(if the runtime of the script reaches MAX_EXECUTION_TIME it is stops.
So if the script run again, it should start where it is ended at last run)
4) Setup a `cron` job to call your script as often as you need.
如果您像这样创建脚本,则不必执行更多操作,而是将url-s放入db表或csv文件,然后等待电子邮件。