Search code examples
javascriptphpajaxfile-get-contents

file_get_contents alternative for large files on ajax upload


Apparently large files do not work with php's file_get_contents. What is the alternative if it apparently is a "stack overflow" issue?

HTML File

<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 File

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));

To better clarify, the echo's aren't resulting in anything


Solution

  • Pretty much every DB driver has a method to deal with oversize BLOB data without having to needlessly bloat your memory requirements. Sqlsrv's appears to be that you can specify a PHP stream as an input type.

    I don't have a SQL server to test this with, but your code would look something like:

    $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);
    

    Ref:

    Also, I don't know if you need to output it as base64, but you can also stream that output as well. Base64 can encode 3 bytes of input into 4 bytes of output without padding, so as long as you're using input chunks that are sized at a multiple of 3 you can safely concatenate them together.

    eg:

    $fh = fopen($theFile, 'rb');
    while( $buf = fread($fh, 3072) ) {
      echo base64_encode($buf);
    }
    fclose($fh);