Uploading XML file and parsing it - without temporary files - php

With PHP 5 I would like to upload an XML file via a web form and parse it using SimpleXML.
I've tried few SimpleXML examples and they work fine at my CentOS 6 Linux server.
However, I don't have any experience with handling uploaded files in PHP yet.
Should I use the $_FILES and do I always have to use a temporary file or can it be done completely in memory?
From PHP Cookbook I've copied this example:
<html>
<body>
<?php if ($_SERVER['REQUEST_METHOD'] == 'GET') { ?>
<form method="post" action="<?php echo $_SERVER['SCRIPT_NAME'] ?>"
enctype="multipart/form-data">
<input type="file" name="doc"/>
<input type="submit" value="Send File"/>
</form>
<?php } else {
if (isset($_FILES['doc']) &&
($_FILES['doc']['error'] == UPLOAD_ERR_OK)) {
$oldPath = $_FILES['doc']['tmp_name'];
$newPath = '/tmp/' . basename($_FILES['doc']['name']);
if (move_uploaded_file($oldPath, $newPath)) {
print "File moved from $oldPath to $newPath";
} else {
print "Couldn't move $oldPath to $newPath";
}
} else {
print "No valid file uploaded.";
}
}
?>
</body>
</html>
It works fine and for the print_r statement added by me the following output is printed:
Array
(
[document] => Array
(
[name] => my_file.xml
[type] => text/xml
[tmp_name] => /tmp/phpRD9cYI
[error] => 0
[size] => 1610252
)
)
And I can see the /tmp/my_file.xml file.
My question is though if I can skip the creation of temporary files?
I don't like them because:
They are sometimes security issue
They have to be cleaned up (by a cronjob?)
Their names might collide (probably seldom case unless it's 1)
UPDATE: Also, I don't understand, why can't I read the file at $oldPath? It is not found there and I have to call the move_uploaded_file() and then read the $newPath...

You don't need to save/move the file in a new folder,
if (isset($_FILES['doc']) && ($_FILES['doc']['error'] == UPLOAD_ERR_OK)) {
$xml = simplexml_load_file($_FILES['doc']['tmp_name']);
}
The tempfile generated will be automatically removed when the PHP script finishes. Hope this helps.

Related

Upload Multiple Files HTML5 / PHP

I'm trying to build a basic upload form to add multiple files to a folder, which is processed by PHP.
The HTML code I have is:
<form id="form" action="add-files-php.php" method="POST" enctype="multipart/form-data">
<div class="addSection">Files To Add:<br><input type="file" name="files[]" multiple /></div>
<div class="addSection"><input type="submit" name="submit" value="Add Files" /></div>
</form>
And the PHP to process is:
$file_path = "../a/files/article-files/$year/$month/";
foreach ($_FILES['files']['files'] as $file) {
move_uploaded_file($_FILES["file"]["name"],"$file_path");
}
I can run the PHP without any errors, but the files don't get added to the path folder.
Where am I going wrong with this?
I have a similar code actually in one of my projects. Try it.
foreach ($_FILES['files']['name'] as $f => $name) {
move_uploaded_file($_FILES["files"]["tmp_name"][$f], $file_path);
}
Look at the following page:
http://php.net/manual/en/function.move-uploaded-file.php
EDIT:
Nowhere in the code you provided, does it show that you actually give your file a filename, you simply refer to a path, rather than a path+filename+extension
move_uploaded_file($_FILES["files"]["tmp_name"][$f], $file_path . $name);
modifying my original code sample to be like the second one, should work.
Iterate the $_FILES['files']['error'] array and check if the files are actually uploaded to the server:
$dest_dir = "../a/files/article-files/$year/$month";
foreach ($_FILES["files"]["error"] as $key => $error) {
if ($error == UPLOAD_ERR_OK) {
// The temporary filename of the file stored on the server
$tmp_name = $_FILES["files"]["tmp_name"][$key];
$name = basename($_FILES["files"]["name"][$key]);
// Handle possible failure of the move_uploaded_file() function, too!
if (! move_uploaded_file($tmp_name, "$dest_dir/$name")) {
trigger_error("Failed to move $tmp_name to $dest_dir/$name",
E_USER_WARNING);
}
} else {
// Handle upload error
trigger_error("Upload failed, key: $key, error: $error",
E_USER_WARNING);
}
}
The biggest issue with your code is that you are trying to move $_FILES['files']['name'] instead of $_FILES['files']['tmp_name']. The latter is a file name of temporary file uploaded into the temporary directory used for storing files when doing file upload.
P.S.
Using relative paths is error-prone. Consider using absolute paths with the help of a constant containing path to the project root, e.g.:
config.php
<?php
define('MY_PROJECT_ROOT', __DIR__);
upload.php
<?php
require_once '../some/path/to/project/root/config.php';
$dest_dir = MY_PROJECT_ROOT . "/a/files/article-files/$year/$month";

Uploading file on server apache via php

I'm trying to download a file from my website to my server but can't find why or where I'm doing that wrong.
Here my php code :
$fn = $_FILES['file']['name'];
if (is_writable('.')) {
echo "Writable<BR>";
} else {
echo "Not writable<BR>";
}
$upfile = './'.basename($fn);
echo $upfile.'<BR>';
shell_exec("echo 'baaaaah' > test.baaaah");
$f = $_FILES['file']['tmp_name'];
echo $f.'<BR>';
if (is_uploaded_file($f)) { echo "uploaded<BR>"; } else { echo "not uploaded<BR>";}
$com = "test - f ".$f." && echo 'F' || echo 'N'";
echo $com.'<BR>';
echo shell_exec($com).'<BR>';
if (move_uploaded_file($f,$uploadfile)) {
echo "File transfer OK<BR>";
} else {
echo "File transfer NOK<BR>";
}
print_r($_FILES);
And here the website output :
Writable
./flag.jpg
/tmp/phpyKvhEz
uploaded
test - f /tmp/phpyKvhEz && echo 'F' || echo 'N'
N
File transfer NOK
Array ( [file] => Array ( [name] => flag.jpg [type] => image/jpeg [tmp_name] => /tmp/phpyKvhEz [error] => 0 [size] => 1660 ) )
So first thing I check if my folder is writable (it's not intended to be '.' but I moved to here because the folder I want wasn't working either (same behavior as '.' through...)) => check
Then I try to shell_exec a file here juste to be sure => check, file is on server
Then I check if the temp file is created on the server :
- check, anyway is_uploaded thinks the file is here
- not check, but a test on the temp file doesn't work (and since the file is not supposed to be removed before the end of the script it should see the file here imho ?)
Then I try to make the move_uploaded_file => not check
And I print the $_FILES who shows nothing suspicious (error = 0, file names matches what I see before).
I can't figure what goes wrong nor where a mistake can come from ><
$uploadfile is undefined in your code. Change it or set it to '.' and it should work.

Filehandling, move_uploaded_file gives me no response

Got a script I've used several times, using move_uploaded_file. But what I can't figure out is why it do not respond in any way, no error reports, nothing.
<form> using method="post", target="upload" that is an <iframe>
action="file.php" responds to $_FILES
Correct enctype
Filerights is set to 777
Upload folder "uploads" exists
print_r($_FILES['file']) gives me:
Array
(
[name] => 1392930853.png
[type] => image/png
[tmp_name] => /tmp/php0rZdBf
[error] => 0
[size] => 611
)
The code below illustrates my script, and what I've figured out is that the last line with move_uploaded_file is the cause of my problem as it do not respond at all. As I wrote above, no error, no nothing.
Pastebin to script: http://pastebin.com/49m9Siqi
Got a clue what could be the cause of this?
$destination_path = getcwd().'/uploads/';
//echo $destination_path;
// File handling
$counted = count($_FILES['file']['name']);
$counted = $counted-1;
for ($i=0; $i<=$counted; $i++) {
if ($_FILES['file']['error'][$i] == UPLOAD_ERR_OK) {
$md5file = rand() . rand() . md5($_FILES['file']['name'][$i]) . rand() . rand();
if(move_uploaded_file($_FILES['file']['tmp_name'][$i], $destination_path . $md5file . "." . basename($_FILES['file']['type'][$i]))) { echo 'THIS WILL NOT BE ECHOED OUT ON THE PAGE'; }}}
There was a simple error in my form, as I handle my uploaded files like an array I need to create the array first.... Which I forgot to do in my form.
Wrong
<input type="file" name="file">
Correct
<input type="file" name="file[]">

Can't move/fine APC Uploaded file

As a bit of a follow up to Javascript form won't submit (to view the code I am using visit that link) I am now encountering a problem that I cannot find the file that has been uploaded.
I have added $files = apc_fetch('files_'.$_POST['APC_UPLOAD_PROGRESS']); to the top of my page and this is the output of print_r($files);
Array
(
[theFile] => Array
(
[name] => tt1.mp4
[type] => video/mp4
[tmp_name] => /tmp/php2BEvy7
[error] => 0
[size] => 1050290
)
)
However when I try to run the following code:
if (file_exists($files['theFile']['tmp_name'])) {
$webinarType = strcmp($files['theFile']['type'], 'video/mp4');
if($webinarType == 0) {
$webinarFile = $fileTitle;
$webinarTempName = $files['theFile']['tmp_name'];
} else {
echo 'Webinar must be .mp4';
}
} else {
echo "No File";
}
I get the No File output.
I have ssh'd into the server and the file is not in /tmp/, /path/to/public_html/tmp/ or path/to/file/tmp/ all of which exist.
I have tried to use move_uploaded_file() but as this is executed on all file inputs I can't get the tmp_name dynamically due to my limited knowledge of javascript.
tl;dr version; Where is my file gone and how can I find it?
NOTE; This form did work before the APC intevention and I am running wordpress in case that affects anything.
Fixed this one on my own as well.
In the progress.php file (found on the other question) I modified the elseif statement with this:
elseif(($s_progressId = $_POST['APC_UPLOAD_PROGRESS']) || ($s_progressId = $_GET['APC_UPLOAD_PROGRESS']))
{
// If the file has finished uploading add content to APC cache
$realpath = realpath($PHP_SELF);
$uploaddir = $realpath . '/tmp/';
foreach ($_FILES as $file) {
if(!empty($file['name'])) {
$uploaded_file = $file['name'];
$moveme = $uploaddir.$uploaded_file;
move_uploaded_file($file['tmp_name'], $moveme);
}
}
apc_store('files_'.$s_progressId, $_FILES);
die();
}
That way I could iterate through the $_FILES array without knowing the name of the input. I noticed that it loops through a couple of times hence the if(!empty()) however in hindsight it's probably best practice anyway.

Invalid file extension when uploading from Sharepoint

I have a website up and running which makes use of file uploads. Everything is working fine, except for one of the users. They are using IE8 to upload files from their SharePoint server to the website. When I look at the $_FILES variable in PHP the 'name' key looks like this:
somefilename[1]
Instead of
somefilename.pdf
The uploads are then blocked, because the extension is not allowed. Has anyone ever dealt/seen this before? It looks like a temporary name, or a hidden file extension.
Edit:
Some of you requested the $_FILES variable:
[Filedata] => Array
(
[name] => Algemene%20Voorwaarden%20Corporate%20Services%202011[2]
[type] => application/octet-stream
[tmp_name] => /tmp/phps19zye
[error] => 0
[size] => 148021
)
This should be a PDF file. I need the extension, not only for security reasons, the [type] would be better suited for that, but also for presentation and functionality. I need to display the correct icon for a file type, and separate images for processing.
The HTML form is just a basic test form:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<form action="uploadtest3.php" method="post" enctype="multipart/form-data">
<input type="file" name="file_upload" id="file_upload" />
<br /><input type="submit" value="Uploaden" />
</form>
</body>
</html>
The PHP file is the following:
$targetFolder = '/uploadtests/uploads3';
if (!empty($_FILES)) {
$tempFile = $_FILES['file_upload']['tmp_name'];
$targetPath = $_SERVER['DOCUMENT_ROOT'] . $targetFolder;
$targetFile = $targetPath . $_FILES['file_upload']['name'];
move_uploaded_file($tempFile,$targetFile);
echo "OK";
}
Introduction
Have seen this issue before but am not sure what caused it. I would not even like to call it an error because some files extension can be intentionally removed or altered for malicious purpose.
The most important thing is validating file properly and worry less if a file has extension or not
Reasons :
File Extension Can easily be faked and it would be bad if your application relies on file extension only for validation
$_FILES ['file_upload']['type'] would return application/octet-stream for all files with not extension so it not not also a option for validation
Since its a browser issue then its a Client Related Problem so you don't have any control. If you are able to manage this you would definitely increase user experience
Simple Patch
The solution is very simple. All you need to validate your file with FILEINFO and fix any extension issue to your uploaded file.
You also need to validated all uploaded file based on their Mime Type ... and remove any invalid file.
Prove of Concept
$allowedTypes = array (
"pdf" => "application/pdf"
);
$pathFinal = "final";
$pathTemp = "temp";
try {
if (! empty ( $_FILES )) {
$tempFile = $_FILES ['file_upload'] ['tmp_name'];
$fileName = $_FILES ['file_upload'] ['name'];
$destinationTemp = $pathTemp . DIRECTORY_SEPARATOR . $fileName;
$destinationFinal = $pathFinal . DIRECTORY_SEPARATOR . $fileName;
/**
* Move To tempary File
*/
move_uploaded_file ( $tempFile, $destinationTemp );
$fileMime = mimeInfo ( $destinationTemp );
$key = array_search ( $fileMime, $allowedTypes );
/**
* Validate Mime Type
*/
if (empty ( $key )) {
unlink ( $destinationTemp );
throw new Exception ( "File Type not Supported" );
}
/**
* Fix Extention Issues
*/
$ext = pathinfo ( $destinationTemp, PATHINFO_EXTENSION );
if (empty ( $ext )) {
$destinationFinal .= "." . $key;
}
/**
* Transfer File to Original Location
*/
copy ( $destinationTemp, $destinationFinal );
unlink ( $destinationTemp );
echo "OK";
}
} catch ( Exception $e ) {
echo "ERROR :", $e->getMessage ();
}
Function Used
function mimeInfo($file) {
return finfo_file ( finfo_open ( FILEINFO_MIME_TYPE ), $file );
}
somefilename appears to be an array. Are your users selecting more than one file to upload?? You need to limit the number of files allowed to upload, or catch the array and handle it properly. You might also ensure that Sharepoint is set to allow multiple file uploads.
Also, I found information regarding the way that IE8 passes the file upload to the server. The source article states:
Additionally, the “Include local directory path when uploading files” URLAction has been set to "Disable" for the Internet Zone. This change prevents leakage of potentially sensitive local file-system information to the Internet. For instance, rather than submitting the full path C:\users\ericlaw\documents\secret\image.png, Internet Explorer 8 will now submit only the filename image.png.
This means, if your code (or Sharepoint) is looking to delimit the folder structure from filename by PATH_SEP, then with IE8 it will obviously fail.
You should check the file type not by extension but by Mime type. Use the variable $_FILES["uploaded_file"]["type"] to get the Mime type.
This way users cannot tamper with the extension with weird ASCII characters, and you know what file is what reliably.

Categories