PHP - Read content of BLOB file - php

I uploaded a *.mp4 video and converted it to a Blob type using JavaScript's new Blob() function.
I send this Blob to PHP, using AJAX.
Now I want to read the content of this Blob inside PHP. In other words, I need the binary data of this Blob and want to store it into a PHP variabele.
However, it seems impossible to read a Blob file with PHP, since fread, fopen and file_get_contents are failing all! When I'm opening the Blob URL in my browser the video is playing fine.
My question is, how do I get the binary data of this Blob with PHP, without installing extensions/libraries?
var_dump($_FILES['video']);
Array
(
[name] => blob
[type] => video/mp4
[tmp_name] => C:\xampp\tmp\php43B8.tmp
[size] => 58
[error] => 0
)
// Try 1
if ($stream = fopen($_FILES['video']['tmp_name'], 'r')) {
echo stream_get_contents($stream, filesize($_FILES['video']['tmp_name']));
fclose($stream);
}
// Try 2
if ($fp = fopen($_FILES['video']['tmp_name'], 'r')) {
echo fread($fp, filesize($_FILES['video']['tmp_name']));
fclose($fp);
}
// Try 3
file_get_contents($_FILES['video']['tmp_name'])
Result is always: blob:http://localhost/d53e40bd-686b-46c8-9e81-94789351466f

I know this is a late reply and you may have fixed this issue already but heres what I did for my BLOB processing. Since the blob is already uploaded to the TEMP file location, we first move the uploaded file somewhere using PHP's move_uploaded_file function. From there, you can read contents and such and then delete the file from your server when processing is completed.
Heres a very basic exampleusing an image file:
// Ajax data for posting the blob, remember to set process data to false
formData.append('code', 'uploadedImage');
formData.append('image', blob);
var url = "script.upload.php";
$.ajax({
type: 'POST',
url: url,
data: formData,
processData: false,
contentType: false,
success: function (data) {}
});
// PHP Code for uploading the file to the server
if ($_POST['code'] == "uploadedImage") {
$data = $_FILES['image']['tmp_name'];
move_uploaded_file($data, $_SERVER['DOCUMENT_ROOT'] . "/img/" . time() . ".png");
}
We now have a file like 1542839470.png at our base directory / images location. From here, the image can now be read, moved, streamed, stored, whatever. I am using a handy plugin called Croppie to resize, rotate and crop my images as well for anyone looking for a neat tool. By processing them first, I can avoid having to do anything with them after. As you are doing video, this won't apply in your specific case, but it's a handy plugin for people doing similar stuff (like me).
Once you are done with the file, either by curl to YouTube API or whatever processing you do with the finished file, you can simply delete the file using the following. Cache the video or file name and location from above (simple to do by setting a location $var) and feed that into this command.
unlink("path_to_file_location"); //delete it

Related

Why is my blob reading as an array?

I have an HTML5 audio recorder which produces an audio blob (recorder.js by Matt Diamond) and executes a jquery ajax call to my PHP file.
function audioUpload() {
recorder && recorder.exportWAV(function(blob) {
//first look at the blob
console.log(blob);
var fd = new FormData();
fd.append('audioBlob', blob);
var audioBlob = fd.get('audioBlob');
//second look at the blob
console.log(audioBlob);
$.ajax({
method: "POST",
data: fd,
contentType: false,
processData: false,
url: "audioSend.php",
}).done(function(data) {
console.log(data);
})
});
There are two console.log functions here that report the blob:
In the first, the console reads as a blob. 1 In another part of the code I create an object URL with this and can play the audio using an HTML5 audio tag, so it's working.
In the second, the console reads it as a file. 2 I can understand this, as blobs are file-like objects by definition. Still, I'm not sure why it isn't reported as a blob like the first instance.
The formData object is posted to audioSend.php where I get the value and insert it into my DB.
$audioBlob = $_FILES['audioBlob'];
$results = mysqli_query($connection, "INSERT INTO audioLog (audio) VALUES ('$audioBlob')");
echo ($audioBlob);
Attempting to insert the blob value into my DB throws an "Array to String Conversion" error, and echoing $audioBlob confirms that it is read as an array. The value shown in my MYSQL DB Blob column is only a few bytes as a result, and not the much larger audio blob object that I want.
Why is the blob read as an array, and how can I get the REAL blob value be inserted into my DB?
You are POSTing the data, so access it via $_POST:
$audioBlob = $_POST['audioBlob'];
Also, use prepared statements as you are vulnerable to SQL injection.
Taking a second look at your code and, while I'm no JS programmer, it looks like you've disabled any sort of graceful POST and have just crammed the raw data into a POST request.
If you want to get this data you'll have to open the php://input stream which contains the un-processed POST body. Eg:
$f_in = fopen('php://input', 'rb');
$f_out = fopen($APPROOT.'/files/foo.bin', 'wb');
while( ! feof($f_in) ) {
$buf = fread($f_in, 4096);
fwrite($f_out, $buf);
}
fclose($f_in);
fclose($f_out);
Which will write the POST data to the file $APPROOT.'/files/foo.bin' 4KB at a time without cramming the entire thing into memory first.
If you want to upload it as a file and have it available in $_FILES you'll have to look into how to properly upload a file via whatever JS library that is.

Send a file (type audio) without input type="file" in ajax

I create a file at the client (record) and then I'd send it on my remote server. However I can not find how to do it without using an input file, I have the file path but when I need to send it by ajax is not detected in $ _FILES side PHP. If I create a blob it works but the file does not match the recording.
Is it possible?
[UPDATE 1]
The file is a audio/mpeg, this file is created after an audio recording, where I get the location and I can play it again. I need to recover without the user clicks on a file input
HTML
<form enctype="multipart/form-data" id="form_message" method="POST">
<textarea name="message" id="message" value="" placeholder="Ecris quelque chose"></textarea>
<input type="submit" style="display:none;" value="Valider"/>
</form>
JS
fd = new FormData();
fd.append('audiofile', 'filepath.mp3');
// other data
function submit_form_message(fd){
$.ajax({
type: 'POST',
url: "url",
data: fd,
processData: false,
contentType: false,
success: function(data){}
});
}
PHP
if($_FILES['audiofile']['size'] !=0){
if ($_FILES['audiofile']['error'] == 0){
$extensions_valides = array('mp3' , 'wav');
if(in_array($_POST['extension'],$extensions_valides)){
$tmp_name = $_FILES["audiofile"]["tmp_name"];
$name_file = $notId.".".$_POST['extension'];
move_uploaded_file($tmp_name, $_SERVER['DOCUMENT_ROOT']."/Bell/sound/".$name_file);
}
}
}
Found this here, which I think may be your best bet: Using local file for Web Audio API in Javascript
Step 1: create Base 64 sound font
First I need to convert my mp3 to a Base64 encoded string and store it
as JSON. I found a website that does this conversion for me here -
http://www.mobilefish.com/services/base64/base64.php You may need
to remove return characters using a text editor but for anyone that
needs an example I found some piano tones here -
https://raw.github.com/mudcube/MIDI.js/master/soundfont/acoustic_grand_piano-mp3.js
Note that in order to work with my example you're need to remove the
header part data:audio/mpeg;base64,
Step 2: decode sound font to ArrayBuffer
You could implement this yourself but I found an API that does this
perfectly (why re-invent the wheel, right?) -
https://github.com/danguer/blog-examples/blob/master/js/base64-binary.js
Resource taken from - here
Step 3: Adding the rest of the code
Fairly straightforward
var cNote = acoustic_grand_piano.C2;
var byteArray = Base64Binary.decodeArrayBuffer(cNote);
var context = new webkitAudioContext();
context.decodeAudioData(byteArray, function(buffer) {
var source = context.createBufferSource(); // creates a sound source
source.buffer = buffer;
source.connect(context.destination); // connect the source to the context's destination (the speakers)
source.noteOn(0);
}, function(err) { console.log("err(decodeAudioData): "+err); });
Since you're passing a String of Base64 content, you are not sending a raw file, and thus do not need to select a file. You can then decode the Base64 in PHP and write it to a new Audio file on the server.

Convert base 64 to audio Mp3 Format on PHP

I have an "audio" tag with the script (actually a plugin) that receives and saves it as base64. And this works okay.
I am trying to alter the script to send the base64 into the server and convert it to mp3 and display the recorded audio in the page.
This is what I have done so far.
Script to save file through ajax:
$(document).on("click", "#download:not(.disabled)", function(){
Fr.voice.export(function(url){
//$("<a href='"+url+"' download='MyRecording.wav'></a>")[0].click();
var src = url;
$.ajax({
url: $("#base_url").val() + "ajax/saveRecordedVoice",
type: "POST",
data: {"record_src": src},
success: function(result){
alert(result);
}
});
}, "base64");
restore();
});
PHP Script to Convert and Save File:
public function saveRecordedVoice()
{
$audio = $_POST['record_src'];
$decoded = base64_decode($audio);
$file_location = "assets/records/recorded_audio.mp3";
$success = file_put_contents($file_location, $decoded);
if($success){
echo "File Saved";
}else{
echo "Uh-uh!";
}
}
The file was successfully saved as .mp3 in my server but when I try to play it manually, Media player says:
Without knowing which plugin you're using to capture the audio, it's hard to really be sure. However i assume that the:
//$("<a href='"+url+"' download='MyRecording.wav'></a>")[0].click();
actually worked before, meaning that whatever audio you're receiving is direct sound.
Mp3 however is an encoded format, and as such, your media player is probably failing, trying to decode unencoded audio.
Try changing the output ending:
$file_location = "assets/records/recorded_audio.wav";
and see if those files will play for you.
If that does not solve it, you should output the "url" you send as data, to see if it sends unwanted markers/headers along.

Form boundaries and writing php://input to a file in php

So I want users to be able to upload big files without having to worry about the post max size values.
The alternative is using PUT and send a file as raw data.
When using jquery I can do this:
var data = new FormData();
jQuery.each($('#file_upload')[0].files, function(i, file) {
data.append('file-'+i, file);
});
$.ajax({
url: 'upload.php?filename=test.pdf',
data: data,
cache: false,
contentType: false,
processData: false,
type: 'PUT',
});
In PHP I can do this:
$f = fopen($_GET['filename'], "w");
$s = fopen("php://input", "r");
while($kb = fread($s, 1024))
{
fwrite($f, $kb, 1024);
}
fclose($f);
fclose($s);
Header("HTTP/1.1 201 Created");
I am not doing:
$client_data = file_get_contents("php://input");
Since putting the whole file into a variable will surely fill up all memory when uploading huge files.
The thing I cannot figure out is how to write the file data without the form boundaries.
Right now it writes at the top of the file something like this:
------WebKitFormBoundaryVz0ZGHLGxBOCUVQG
Content-Disposition: form-data; name="file-0"; filename="somename.pdf"
Content-Type: application/pdf
and at the bottom something like this:
------WebKitFormBoundaryVz0ZGHLGxBOCUVQG--
So I need to parse the data. But for that I need to read the whole data stream into memory and with large video files I don't want to do that.
I did read something about maybe creating a php://temp stream. But no luck yet with that.
How can I write just the content to a file, without the boundary header? And without first pumping all the data into a variable?
Maybe a combination of fgets to stop reading at a newline and checking for the boundaries:
while($kb = fgets($s, 1024))
{
if(strpos($kb, '------') === false) //or !== 0 for first position
{
fwrite($f, $kb, 1024);
}
}
You can use this (there are many like it). It supports chunked uploads which means you won't hit any post/file max sizes as long as each upload chunk is less than the post max size.
It also includes the PHP code you would need on the server side.
There is no need to recreate the wheel. Just use POST and change PHP's config to bigger limits. Those limits can also be set on a per directory / host basis.
Using .htaccess or your apache.conf
php_value upload_max_filesize 10G
php_value post_max_size 10G
It is also a good idea to adjust other limits, like max_input_time.
Don't forget to relocated the received file using move_uploaded_file to avoid any extra work.

uploading canvas context as image using ajax and php

I have a canvas and I want to upload the canvas context to the server using ajax and php. I want the final output to be an image stored on the server. I have done image uploading using form. But now I want to get the canvas context convert it to image and upload to the server!
So, how can i do that? Any suggestions, algos or solutions are appreciated!
This blog post aptly describes the method of saving canvases onto the server with AJAX queries, I guess this should be fitting for you.
Basically, you will need a var canvasData = testCanvas.toDataURL("image/png"); to retrieve the canvas' contents in JavaScript. This will be a Base64 encoded string, something like this: data:image/png;base64,fooooooooooobaaaaaaaaaaar==.
The following code will make sure the AJAX query sends the contents to the HTML:
var ajax = new XMLHttpRequest();
ajax.open("POST",'testSave.php',false);
ajax.setRequestHeader('Content-Type', 'application/upload');
ajax.send(canvasData);
On the server, in the PHP script, you will have a key named HTTP_RAW_POST_DATA in the $GLOBALS array, this will contain the data we just fetched.
// Remove the headers (data:,) part.
$filteredData=substr($GLOBALS['HTTP_RAW_POST_DATA'], strpos($GLOBALS['HTTP_RAW_POST_DATA'], ",")+1);
// Need to decode before saving since the data we received is already base64 encoded
$decodedData=base64_decode($filteredData);
$fp = fopen( 'test.png', 'wb' );
fwrite( $fp, $decodedData);
fclose( $fp );
Of course, test.png is the filename you will save. The first line is required to remove the data:image/png;base64, part of the encoded image, so that it can later be decoded by base64_decode(). It's output ($decodedData) will be saved to the file.

Categories