I'm using Fine-Uploader with PHP and something wrong happened. When I use stream_copy_to_stream() in the backend, it always returns 0.
Here's my code in the backend:
private function upload_file($file_name, $tmp_name)
{
$result = array(
'is_successful' => true,
'extra_message' => ''
);
$target_path = $this->get_target_file_path($file_name, $tmp_name);
move_uploaded_file($tmp_name, $target_path);
$result['is_successful'] = $this->handle_upload_request($target_path);
if ( $result['is_successful'] ) {
$result['extra_message'] = $target_path;
} else {
$result['extra_message'] = 'Unknown error occured.<br />';
}
return $result;
}
private function handle_upload_request($path)
{
$input = fopen("php://input", "r");
$temp = tmpfile();
$real_size = stream_copy_to_stream($input, $temp);
fclose($input);
echo $real_size;
if ($real_size != $this->get_size()){
return false;
}
$target = fopen($path, "w");
fseek($temp, 0, SEEK_SET);
stream_copy_to_stream($temp, $target);
fclose($target);
return true;
}
However, the $real_size always equal to 0. Strangely, the file can be uploaded successfully sometimes, but sometimes not.
I think maybe it's due to permission in Linux. Because I found that when I uploaded a file, the mod of the file is 644(But I think 644 is enough). And this problem also exists in Windows.
What's wrong with it?
You should not be using php://input. php://input is used to access the raw request body. It is empty for multipart encoded requests. All upload requests sent by Fine Uploader are multipart encoded by default. Instead, you should grab the file associated with the request using the $_FILES superglobal. There is a functional PHP example which will demonstrate this and more for you in the Fine Uploader server Github repo.
If you insist on writing your own PHP code to handle the requests, you really need to read the traditional server-side documentation for Fine Uploader first, which tells you that all upload requests are multipart encoded by default. This is set to the default in order to make it a bit easier to handle upload requests cross-browser, since we need to send the files in a MPE request from IE9 and older always anyway, since IE9 and older do not support uploading files via ajax requests (XHR2).
Related
Hi i have the following code that uploads videos to a server and updates the database accordingly. This code works fine when i run it with a bunch of images and or small video's. See the code below:
for ($i=0; $i<count($_FILES['images']['error']); $i++) {
if ($_FILES['images']['error'][$i] == UPLOAD_ERR_OK) {
$tmpName = $_FILES['images']['tmp_name'][$i];
$name = $_FILES['images']['name'][$i];
$type = $_FILES['images']['type'][$i];
if (strpos($type, 'image') !== false) {
$type = "img";
}elseif(strpos($type, 'video') !== false){
$type = "vid";
}else{
exit();
}
move_uploaded_file(($tmpName), $dir.$name);
$upload = array(
'name'=>$name,
'type'=>$type
);
$uploads[] = $upload;
}
}
But when my client tries to upload a video bigger than 64mb the program doesnt upload it... I already tried to change the max_file_size and other according parameters to allow bigger files. But my clients hosting provider doesnt allow this.
So are there any other ways of uploading big files to my server via my custom cms?
Thomas
So as said in comments. Reference material is below code examples. Trick is to cut the file into chunks that are less than the upload limit. This method can be extended to the point that when a file upload is interrupted you can continu on the last known part. :-)
Basic JavaScript class to assist in uploading the file, determines the chunks to be sent to a PHP server.
function fileUploader() {
// Called when the file is selected
this.onFileSelected = function() {
// Read file input (input type="file")
this.file = this.fileInput.files[0];
this.file_size = this.file.size;
this.chunk_size = (1024 * 1000);
this.range_start = 0;
this.range_end = this.chunk_size;
this.slice_method = 'slice';
this.request = new XMLHttpRequest();
// Start uploading
this.upload();
};
this.upload = function()
{
var self = this,
chunk;
// Last part reached
if (this.range_end > this.file_size) {
this.range_end = this.file_size;
}
// Chunk the file using the slice method
chunk = this.file[this.slice_method](this.range_start, this.range_end);
// Open a XMLHttpRequest
var endpoint = "/url/to/php/server/for/processing";
this.request.open('PUT', (endpoint));
this.request.overrideMimeType('application/octet-stream');
this.request.send(chunk);
// Make sure we do it synchronously to prevent data corruption
this.request.onreadystatechange = function()
{
if (self.request.readyState == XMLHttpRequest.DONE && self.request.status == 200) {
self.onChunkComplete();
}
}
};
this.onChunkComplete = function()
{
if (this.range_end === this.file_size)
{
// We are done, stop uploading
return;
}
this.range_start = this.range_end;
this.range_end = this.range_start + this.chunk_size;
this.upload();
};
}
And for the PHP bit:
...
$out = fopen("{$filePath}.partial", "a+");
fwrite($out, file_get_contents("php://input"));
fclose($out);
...
Big warning here, make sure to properly validate and take security measures to ensure the safety of your clients upload function. You are writing the raw PHP input to a file.
When the upload is done you can rename the file to it's original name including the correct extension.
Reference material:
http://creativejs.com/tutorials/advanced-uploading-techniques-part-1/index.html
https://secure.php.net/manual/en/wrappers.php.php
In a nutshell.. it's break the file into small chunks using a processor, upload the files using conventional methods (like you would normally upload a file), append the input to a temporarily file. Some pitfalls I encountered were sending extra params and alike to the endpoint, avoid those as it's appended to the file and it will corrupt your file.
I'm facing an issue with file uploads using Yii2 framework, but I think that question goes deeper than a framework problem. I have an app that allow the user do pdf files uploads, until here my app works fine but I'm in trouble when some smartass rename the filename extension from anything to pdf. The app isn't validating this kind of trick.
I tried without success to validate the mimetype. Now I'm looking for another way.
Anyone know how to block this kind of cheat?
Its better to keep it simple and just use this
<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if(finfo_file($finfo,$filename) == 'application/pdf'){
// input file is pdf
}
?>
Since you said its not working for you you can try these
if you are using a Linux server you can use the shell commands to check them mime type
<?php
function detectMimeType($filename='')
{
$filename = escapeshellcmd($filename);
$command = "file -b --mime-type -m /usr/share/misc/magic {$filename}";
$mimeType = shell_exec($command);
return trim($mimeType);
}
?>
Or you can try this method .Here we assume that Pdf file starts with a %PDF string .[usually it does start with %PDF].
<?php
function detectFileType($filename='')
{
$handle = fopen($filename, "rb");
$contents = fread($handle, 4);
fclose($handle);
if($contents == "%PDF")
{
return "application/pdf";
}
else
{
return "application/octet-stream"; //unknown type
}
}
?>
[this code is not tested ]
Refer these links you will get some more info about what went wrong
http://php.net/manual/en/function.mime-content-type.php
http://php.net/manual/en/ref.fileinfo.php
the best way is to check mime type of file :
http://php.net/manual/en/function.finfo-file.php
<?php
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if(finfo_file($finfo,$filename) == 'application/pdf'){
// input file is pdf
}
finfo_close($finfo);
?>
The problem was solved using the mime_content_type function.
Check the function here php.net
This function returns the real mime type.
JSFIDDLE
I'm using filedrop.js to create a file repository structure within my app. The above noted JSFIDDLE has all of the Javascript / jQuery / HTML and CSS code for this small module. While everything on the client end seems to be functioning properly (files can be DnD'd, progress bar acts correctly, console shows proper event triggers), the result on the server-side is always an empty $_FILES variable. My PHP (ajax.receiveFile.php) is as follows:
var_dump($_FILES);
ob_start();
$callback = &$_REQUEST['fd-callback'];
$job_id = &$_REQUEST['job_id'];
$subdir = &$_REQUEST['subdir'];
$j = loadJob($job_id);
$save_path = "D:\\JobFiles\\" . $j->gOrderNumber() . "\\" . $subdir . "\\";
if ( ($_FILES['fd-file']['size'] > 0) && is_uploaded_file($_FILES['fd-file']['tmp_name']) ) {
$name = $_FILES['fd-file']['name'];
if (move_uploaded_file($_FILES['fd-file']['tmp_name'], $save_path.$name)) {
$j->addAttachment($subdir,$name);
echo 'true';
} else {
echo 'false';
}
}
ob_end_flush();
FileDrop.js seems to be doing what it is supposed to do, as shown here:
I read here on SO that using the same element name over multiple input types of "file" can cause errors but I'm not sure that is the case here. I have double- and triple-checked the permissions on both the TEMP and TARGET upload folders, I have confirmed that all PHP variables are set as needed via visual inspection and PHPINFO(). The server config is PHP 5.4 on IIS7.
If anyone has any ideas on what else to look for, please contribute. Thanks!
This works for me:
file_put_contents('uploads/person/7.jpeg', fopen('php://input', 'r'));
I keep recieving a PHP error, "Call to undefined function getallheaders() in /home/jbird11/public_html/grids/upload.php on line 8"
The upload script basically takes an image that is dragged into an area, and uploads it. When I drag the image, I get this message.
Here is the first 40 or so lines of the php file:
<?php
// Maximum file size
$maxsize = 1024; //Kb
// Supporting image file types
$types = Array('image/png','images/gif','image/jpeg');
$headers = getallheaders();
// LOG
$log = '=== '. #date('Y-m-d H:i:s') . ' ========================================'."\n"
.'HEADER:'.print_r($headers,1)."\n"
.'GET:'.print_r($_GET,1)."\n"
.'POST:'.print_r($_POST,1)."\n"
.'REQUEST:'.print_r($_REQUEST,1)."\n"
.'FILES:'.print_r($_FILES,1)."\n";
$fp = fopen('log.txt','a');
fwrite($fp, $log);
fclose($fp);
header('content-type: plain/text');
// File size control
if($headers['X-File-Size'] > ($maxsize *1024)) {
die("Max file size: $maxsize Kb");
}
// File type control
if(in_array($headers['X-File-Type'],$types)){
// Create an unique file name
$filename = sha1(#date('U').'-'.$headers['X-File-Name']).'.'.$_GET['type'];
// Uploaded file source
$source = file_get_contents('php://input');
// Image resize
imageresize($source, $filename, $_GET['width'], $_GET['height'], $_GET['crop'], $_GET['quality']);
} else die("Unsupported file type: ".$headers['X-File-Type']);
// File path
$path = str_replace('upload.php','',$_SERVER['SCRIPT_NAME']);
// Image tag
echo '<img src="'.$path.$filename.'" alt="image" />';
Any idea what is causing this error? Permissions perhaps? Permission are set to 755. You can see a working demo of this here: http://pixelcakecreative.com/grids/
Any idea how to fix this? Thanks in advance
From the docs:
This function is an alias for apache_request_headers(). Please read the apache_request_headers() documentation for more information on how this function works.
If you're not using apache (with php as a module), this function is not available.
It's an apache related function. Maybe You don't have needed extensions installed?
from the hosting company: It appears that that function is only supported when PHP is run as an Apache module. Our Shared and Reseller servers run PHP as CGI, and unfortunately this cannot be changed. We apologize for any inconvenience.
If that function is absolutely required for your site, you will need to consider upgrading to a VPS, in which case PHP can be installed however you like.
you can use this code to be sure you have such a function not depending on server software configuration:
if (!function_exists("getallheaders"))
{
function getallheaders()
{
$headers = "";
foreach ($_SERVER as $name => $value)
{
if (substr($name, 0, 5) == "HTTP_")
{
$headers[str_replace(" ", "-", ucwords(strtolower(str_replace("_", " ", substr($name, 5)))))] = $value;
}
}
return $headers;
}
}
I am working on a piece of code that I am wanting to "spice" up with jQuery but I can't think of a way to actually make it work. I am sure its simple, I just need a little advice to get me going.
I am wanting to create a piece of code that makes an Ajax request out to start a big loop that will download files and then upload them to an S3 bucket of mine. The place where I am stuck is I am wanting to send back a request back to the browser everytime a file is uploaded and output a string of text to the screen upon completion.
I don't have any of the frontend code working... just trying to get my head wrapped around the logic first... any ideas?
PHP Backend Code:
<?php
public function photos($city) {
if(isset($city))
$this->city_name = "{$city}";
// grab data array from Dropbox folder
$postcard_assets = $this->conn->getPostcardDirContent("{$this->city_name}", "Photos", TRUE);
$data = array();
foreach($postcard_assets['contents'] as $asset) {
//only grab contents in root folder... do not traverse into sub folders && make sure the folder is not empty
if(!$asset['is_dir'] && $asset['bytes'] > 0) {
// get information on file
$file = pathinfo($asset['path']);
// download file from Dropbox
$original_file = $this->conn->downloadFile(str_replace(" ", "%20", $asset['path']));
// create file name
$file_name = $this->cleanFileName($file['basename']);
// write photo to TMP_DIR ("/tmp/photos/") for manipulation
$fh = fopen(self::TMP_DIR . $file_name, 'w');
fwrite($fh, $original_file);
fclose($fh);
// Resize photo
$this->resize_photo($file_name);
// hash file name
$raw_file = sha1($file_name);
// create S3 hashed name
$s3_file_name = "1_{$raw_file}.{$file['extension']}";
// Upload manipulated file to S3
$this->s3->putObject($s3_file_name, file_get_contents(self::TMP_DIR . $file_name), $this->photo_s3_bucket, 'public-read');
// check to see if file exists in S3 bucket
$s3_check = $this->s3->getObjectInfo($s3_file_name, $this->photo_s3_bucket);
// if the file uploaded successully to S3, load into DB
if($s3_check['content-length'] > 0) {
$data['src'] = $s3_file_name;
$data['width'] = $this->width;
$data['height'] = $this->height;
Photo::create_postcard_photo($data, "{$this->city_name}");
// Now that the photo has been uploaded to S3 and saved in the DB, remove local file for cleanup
unlink(self::TMP_DIR . $file_name);
echo "{$file_name} uploaded to S3 and resized!<br />";
}
}
}
// after loop is complete, kill script or nasty PHP header warnings will appear
exit();
}
?>
The main problem is that with PHP, the output is buffered so it won't return a line at a time. You can try and force the flush but it's not always reliable.
You could add an entry to the DB for each file that is exchanged and create a seperate API to get the details of what has completed.
Generally, Jquery will wait till the request has finished before it allows you to manipulate data from a HTTP request.