file_get_contents ajax 上传大文件的替代方法
file_get_contents alternative for large files on ajax upload
显然大文件不适用于 php 的 file_get_contents。如果它显然是 "stack overflow" 问题,还有什么替代方案?
HTML 文件
<form id='test'>
<input type='file' name='Receipt' />
</form>
<button onClick='save_Receipt();'>Save</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
function save_Receipt(){
var ticketData = new FormData($('form#test')[0]);
$.ajax({
cache: false,
processData: false,
contentType: false,
url:"cgi-bin/php/post/testimage.php",
method:"POST",
data:ticketData,
success:function(code){}
});
}
</script>
PHP 文件
ini_set('memory_limit','512M');
$img = file_get_contents($_FILES['Receipt']['tmp_name']);
echo base64_encode($img);
echo $img;
sqlsrv_query($Portal,
" INSERT INTO Portal.dbo.[File]([Name], [Type], [Data], [User], Ticket)
VALUES(?, ?, ?, ?, ?);", array($_FILES['Receipt']['name'], $_FILES['Receipt']['type'], array(base64_encode($img), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY), SQLSRV_SQLTYPE_VARBINARY('max')), $_SESSION['User'], 2094378));
为了更好地说明,回声不会导致 任何结果
几乎每个数据库驱动程序都有一种方法来处理超大的 BLOB 数据,而不必不必要地增加内存需求。 Sqlsrv 似乎是您可以将 PHP 流指定为输入类型。
我没有 SQL 服务器来测试它,但是你的代码看起来像这样:
$fh = fopen($theFile, 'rb');
$stmt = sqlsrv_prepare(
$conn,
'INSERT INTO blobTable VALUES (?)',
[
[$fh, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY), SQLSRV_SQLTYPE_BLOB]
]
);
$stmt->execute();
fclose($fh);
参考:
- https://secure.php.net/manual/en/book.sqlsrv.php
- https://php.net/manual/en/function.sqlsrv-prepare.php
- https://php.net/manual/en/sqlsrv.constants.php
- https://docs.microsoft.com/en-us/sql/connect/php/how-to-specify-php-data-types?view=sql-server-2017
此外,我不知道您是否需要将其输出为 base64,但您也可以流式传输该输出。 Base64 可以将 3 个字节的输入编码为 4 个字节的输出而无需填充,因此只要您使用大小为 3 的倍数的输入块,您就可以安全地将它们连接在一起。
例如:
$fh = fopen($theFile, 'rb');
while( $buf = fread($fh, 3072) ) {
echo base64_encode($buf);
}
fclose($fh);
显然大文件不适用于 php 的 file_get_contents。如果它显然是 "stack overflow" 问题,还有什么替代方案?
HTML 文件
<form id='test'>
<input type='file' name='Receipt' />
</form>
<button onClick='save_Receipt();'>Save</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
function save_Receipt(){
var ticketData = new FormData($('form#test')[0]);
$.ajax({
cache: false,
processData: false,
contentType: false,
url:"cgi-bin/php/post/testimage.php",
method:"POST",
data:ticketData,
success:function(code){}
});
}
</script>
PHP 文件
ini_set('memory_limit','512M');
$img = file_get_contents($_FILES['Receipt']['tmp_name']);
echo base64_encode($img);
echo $img;
sqlsrv_query($Portal,
" INSERT INTO Portal.dbo.[File]([Name], [Type], [Data], [User], Ticket)
VALUES(?, ?, ?, ?, ?);", array($_FILES['Receipt']['name'], $_FILES['Receipt']['type'], array(base64_encode($img), SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY), SQLSRV_SQLTYPE_VARBINARY('max')), $_SESSION['User'], 2094378));
为了更好地说明,回声不会导致 任何结果
几乎每个数据库驱动程序都有一种方法来处理超大的 BLOB 数据,而不必不必要地增加内存需求。 Sqlsrv 似乎是您可以将 PHP 流指定为输入类型。
我没有 SQL 服务器来测试它,但是你的代码看起来像这样:
$fh = fopen($theFile, 'rb');
$stmt = sqlsrv_prepare(
$conn,
'INSERT INTO blobTable VALUES (?)',
[
[$fh, SQLSRV_PARAM_IN, SQLSRV_PHPTYPE_STREAM(SQLSRV_ENC_BINARY), SQLSRV_SQLTYPE_BLOB]
]
);
$stmt->execute();
fclose($fh);
参考:
- https://secure.php.net/manual/en/book.sqlsrv.php
- https://php.net/manual/en/function.sqlsrv-prepare.php
- https://php.net/manual/en/sqlsrv.constants.php
- https://docs.microsoft.com/en-us/sql/connect/php/how-to-specify-php-data-types?view=sql-server-2017
此外,我不知道您是否需要将其输出为 base64,但您也可以流式传输该输出。 Base64 可以将 3 个字节的输入编码为 4 个字节的输出而无需填充,因此只要您使用大小为 3 的倍数的输入块,您就可以安全地将它们连接在一起。
例如:
$fh = fopen($theFile, 'rb');
while( $buf = fread($fh, 3072) ) {
echo base64_encode($buf);
}
fclose($fh);