Several problems with file uploading in PHP - php

I am new to PHP. Currently I am learning how to do PHP file upload validation and following an implementation proposed in https://www.php.net/manual/en/features.file-upload.php
I created a HTML file upload form, send a POST request to process.php then if it passed the validation check, server will redirect to another page called file.php containing the link of the uploaded file for downloading.
Here is my code:
process.php
<?php
try {
if (!isset($_FILES['file']['error']) || is_array($_FILES['file']['error'])) {
throw new RuntimeException("Invalid parameters.");
}
switch ($_FILES['file']['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
throw new RuntimeException("No file uploaded.");
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new RuntimeException("File size exceeded the limit.");
default:
throw new RuntimeException("Unknown errors.");
}
if ($_FILES['file']['size'] > 3 * 1024 * 1024) {
//exceeded 3 MB
throw new RuntimeException("File size exceeded the limit.");
}
$finfo = new finfo(FILEINFO_MIME_TYPE);
if (false === $ext = array_search(
$finfo->file($_FILES['file']['tmp_name']),
array(
'jpg' => 'image/jpeg',
'png' => 'image/png',
'gif' => 'image/gif',
),
true
)) {
throw new RuntimeException("File type not allowed.");
}
$destpath = __DIR__ . "/" . sprintf("uploads/%s.%s", sha1_file($_FILES['file']['tmp_name']), $ext);
if (!move_uploaded_file(
$_FILES['file']['tmp_name'],
$destpath
)) {
throw new RuntimeException("Failed to move uploaded file.");
}
header("Location: file.php");
exit();
} catch (RuntimeException $e) {
echo $e->getMessage();
}
?>
file.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<?php
include "process.php";
?>
<p><?php $destpath;?></p><br>
Download
</body>
</html>
Here are some problems:
The $destpath in file.php is supposed to contain the file path ($destpath is a variable in process.php, which I included in file.php) but it appears to be a variable containing nothing.
After header("Location: file.php) I called exit() method, but the "Invalid parameters." message still displayed. I don't know why it passed all validation check (because it redirected to file.php successfully) but it still displayed that message (which is for the first check). Also I called exit() but the echo $e->getMessage() in the catch block still got executed.
I created uploads folder in terminal, and the folder had the privilege 755. I have to change it to 777 in terminal so move_uploaded_file() in process.php can work properly (maybe because the scripts are executed by XAMPP, which is not the owner of the folder). Is there any common practice for this uploading procedure? Because the folder with 777 privilege is insecure, I want it to be 755 and the move_uploaded_file() still works. Currently I am using XAMPP on MacOS.
I am new to PHP, please bear with me. Thank you!

Related

run php inside website uploaded from user

Christian pleasure.
I start with telling you: "sorry for my english but in years of studies i don't speak very well".
Anyway....
I've a website developed with design pattern MVC, in this website the user can upload php file and run his. For using this file uploaded, the user have an a token: example.com/home/profile/advance?token=XXXXXXXXXXXXXX
I would that this file uploaded from user can't interact with my server as if it were inside a virtual machine.
It possible?
I hope I explained myself.
That's absolute possible. Just append the user's token to your form uploader:
<?php
$token = 'xxx';
?>
<form action="home/profile/advance?token=<?php echo htmlentities(urlencode($token)); ?>" method="post" enctype="multipart/form-data">
<input type="file" name="fileToUpload" id="fileToUpload">
<input type="submit" value="Upload File" name="submit">
This will make a $_POST to home/profile/advance?token=xxx.
Note that a server-side generated token should only contain alphanumeric characters, but it's best to wrap it in htmlentities() and urlencode() to be safe.
However, note that allowing users to upload (and run) their own PHP files is a huge security risk! I would strongly recommend not allowing them to run PHP, but instead limiting allowed uploads to raw .txt files. There's several different vectors to consider here, so I would recommend implementing the following (courtesy of CertaiN, with minor modification):
<?php
header('Content-Type: text/plain; charset=utf-8');
try {
// Undefined | Multiple Files | $_FILES Corruption Attack
// If this request falls under any of them, treat it invalid.
if (
!isset($_FILES['upfile']['error']) ||
is_array($_FILES['upfile']['error'])
) {
throw new RuntimeException('Invalid parameters.');
}
// Check $_FILES['upfile']['error'] value.
switch ($_FILES['upfile']['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
throw new RuntimeException('No file sent.');
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new RuntimeException('Exceeded filesize limit.');
default:
throw new RuntimeException('Unknown errors.');
}
// You should also check filesize here.
if ($_FILES['upfile']['size'] > 1000000) {
throw new RuntimeException('Exceeded filesize limit.');
}
// DO NOT TRUST $_FILES['upfile']['mime'] VALUE !!
// Check MIME Type by yourself.
$finfo = new finfo(FILEINFO_MIME_TYPE);
if (false === $ext = array_search(
$finfo->file($_FILES['upfile']['tmp_name']),
array(
'txt' => 'text/plain',
),
true
)) {
throw new RuntimeException('Invalid file format.');
}
// You should name it uniquely.
// DO NOT USE $_FILES['upfile']['name'] WITHOUT ANY VALIDATION !!
// On this example, obtain safe unique name from its binary data.
if (!move_uploaded_file(
$_FILES['upfile']['tmp_name'],
sprintf('./uploads/%s.%s',
sha1_file($_FILES['upfile']['tmp_name']),
$ext
)
)) {
throw new RuntimeException('Failed to move uploaded file.');
}
echo 'File is uploaded successfully.';
} catch (RuntimeException $e) {
echo $e->getMessage();
}

error upon uploading image no such path or directory

Good day, I have been following a tutorial and have worked really hard to make this script work, I have managed to fix many things however the one constant problem I'm getting is:
No such file or directory in /home/xxxxxxx/public_html/regForm.php on line 93
What I am trying to acomplish is get user to upload a profile pic to my live server / website upon registration, here is part of my form and the code below:
I would greatly appreciate it if a more experienced user can give it a scan and advise to where I am going wrong, thanx in advance
HTML FORM
<form ENCTYPE="multipart/form-data" name="registration-form" id="regForm" method="post" action="regForm.php">
:
:
Upload Picture: <INPUT NAME="file_up" TYPE="file">
<input type="submit" value="Register" name="register" class="buttono" />
</form>
UPLOAD SCRIPT
$file_upload="true";
$file_up_size=$_FILES['file_up']['size'];
echo $_FILES['file_up']['name'];
if ($_FILES['file_up']['size']>250000){
$msg=$msg."Your uploaded file size is more than 250KB
so please reduce the file size and then upload.<BR>";
$file_upload="false";
}
if (!($_FILES['file_up']['type'] =="image/jpeg" OR $_FILES['file_up']['type'] =="image/gif"))
{
$msg=$msg."Your uploaded file must be of JPG or GIF. Other file types are not allowed<BR>";
$file_upload="false";
}
$file_name=$_FILES['file_up']['name'];
if($file_upload=="true"){
$ftp_server = "xxxxxx";
$ftp_conn = ftp_connect($ftp_server) or die("Could not connect to $ftp_server");
$ftp_username='xxxxxx';
$ftp_userpass='xxxxxx';
$login = ftp_login($ftp_conn, $ftp_username, $ftp_userpass);
$file = $file_name;
// upload file
if (ftp_put($ftp_conn, "public_html/img/userPics", $file, FTP_ASCII)) //here is the problem with the path I suspect
{
echo "Successfully uploaded $file.";
}
else
{
echo "Error uploading $file.";
}
// close connection
ftp_close($ftp_conn);
}
When dealing with images, you need to use a binary format.
FTP_BINARY instead of FTP_ASCII.
As per the manual:
http://php.net/manual/en/function.ftp-put.php
Make sure the path is correct. This can differ from different servers.
You also need a trailing slash here:
public_html/img/userPics/
^
Otherwise, your system will interpret that as:
userPicsIMAGE.JPG rather than the intended userPics/IMAGE.JPG
Yet, you may need to play around with the path itself. FTP is a bit tricky that way.
I.e.:
/home/xxxxxxx/public_html/userPics/
img/userPics/
../img/userPics/
Depending on the file's area of execution.
Root > ftp_file.php
-img
-userPics
The folder also needs to have proper permissions to be written to.
Usually 755.
Use error reporting if your system isn't already setup to catch and display error/notices:
http://php.net/manual/en/function.error-reporting.php
An example from the FTP manual:
<?php
ftp_chdir($conn, '/www/site/');
ftp_put($conn,'file.html', 'c:/wamp/www/site/file.html', FTP_BINARY );
?>
Another thing though, the use of of "true" and "false". You're most likely wanting to check for truthness
$file_upload=true;
rather than a string literal $file_upload="true";
same thing for
if($file_upload=="true")
to
if($file_upload==true)
and for $file_upload="false"; to check for falseness
to $file_upload=false;
Read the manual on this:
http://php.net/manual/en/language.types.boolean.php
This is the simplest type. A boolean expresses a truth value. It can be either TRUE or FALSE.
Test your FTP connection, pulled from https://stackoverflow.com/a/3729769/
try {
$con = ftp_connect($server);
if (false === $con) {
throw new Exception('Unable to connect');
}
$loggedIn = ftp_login($con, $username, $password);
if (true === $loggedIn) {
echo 'Success!';
} else {
throw new Exception('Unable to log in');
}
print_r(ftp_nlist($con, "."));
ftp_close($con);
} catch (Exception $e) {
echo "Failure: " . $e->getMessage();
}
Naming conventions:
I also need to note that on LINUX, userPics is not the same as userpics, should your folder name be in lowercase letters.
Unlike Windows, which is case-insensitive.

Can I create a php script to act as FTP

I have a php script I'm using to upload zip files to my ftp and automatically unzip them.
I wonder if there is a finished php script to delete folders and files on my ftp.
Reason I'm asking is because I save so much time doing the zip upload and unzip process instead of unzipping locally and then upload the files.
So now my problem is that it takes quite allot of time to delete folders and files using Filezilla and I want to speed that up.
Anyone with a working solution?
Edit:
Here is my unzip code that I'm using:
<?php
/* Simple script to upload a zip file to the webserver and have it unzipped
Saves tons of time, think only of uploading Wordpress to the server
Thanks to c.bavota (www.bavotasan.com)
I have modified the script a little to make it more convenient
Modified by: Johan van de Merwe (12.02.2013)
*/
function rmdir_recursive($dir) {
foreach(scandir($dir) as $file) {
if ('.' === $file || '..' === $file) continue;
if (is_dir("$dir/$file")) rmdir_recursive("$dir/$file");
else unlink("$dir/$file");
}
rmdir($dir);
}
if($_FILES["zip_file"]["name"]) {
$filename = $_FILES["zip_file"]["name"];
$source = $_FILES["zip_file"]["tmp_name"];
$type = $_FILES["zip_file"]["type"];
$name = explode(".", $filename);
$accepted_types = array('application/zip', 'application/x-zip-compressed', 'multipart/x-zip', 'application/x-compressed');
foreach($accepted_types as $mime_type) {
if($mime_type == $type) {
$okay = true;
break;
}
}
$continue = strtolower($name[1]) == 'zip' ? true : false;
if(!$continue) {
$message = "The file you are trying to upload is not a .zip file. Please try again.";
}
/* PHP current path */
$path = dirname(__FILE__).'/'; // absolute path to the directory where zipper.php is in
$filenoext = basename ($filename, '.zip'); // absolute path to the directory where zipper.php is in (lowercase)
$filenoext = basename ($filenoext, '.ZIP'); // absolute path to the directory where zipper.php is in (when uppercase)
$targetdir = $path . $filenoext; // target directory
$targetzip = $path . $filename; // target zip file
/* create directory if not exists', otherwise overwrite */
/* target directory is same as filename without extension */
if (is_dir($targetdir)) rmdir_recursive ( $targetdir);
mkdir($targetdir, 0777);
/* here it is really happening */
if(move_uploaded_file($source, $targetzip)) {
$zip = new ZipArchive();
$x = $zip->open($targetzip); // open the zip file to extract
if ($x === true) {
$zip->extractTo($targetdir); // place in the directory with same name
$zip->close();
unlink($targetzip);
}
$message = "Your .zip file was uploaded and unpacked.";
} else {
$message = "There was a problem with the upload. Please try again.";
}
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Unzip a zip file to the webserver</title>
</head>
<body>
<?php if($message) echo "<p>$message</p>"; ?>
<form enctype="multipart/form-data" method="post" action="">
<label>Choose a zip file to upload: <input type="file" name="zip_file" /></label>
<br />
<input type="submit" name="submit" value="Upload" />
</form>
</body>
</html>
I don't mean to plug my own work here but there is a script I am selling on a website called Code Canyon called MightyFTP that wraps the complex procedural php ftp functionality into a much simpler OO API.
As far as I am aware deleting a folder requires recursive deletion via the current FTP API so there is little bit of work involved normally.
A link to the script is here "http://codecanyon.net/item/mightyftp/8276375"
If you had my code and you wanted to delete an ftp folder the code to do it is very straight forward as demonstrated below.
require_once("MightyFTP/FTPClient.php");
$myFtpClient = new MightyFTP\FTPClient("yourftpserver", new MightyFTP\FTPCredentials("yourftpusername", "yourftppassword"));
$ftpDirectoryToDelete = $myFtpClient->getFile("/PathToDirectory/");
$parentDir = $ftpDirectoryToDelete->delete(); //The directory and all its children have been deleted. It will then return the parent of the deleted file/folder.
$ftpDirectoryToDelete->rename(""); //Will throw an exception because you will not be able to run an operation on a file/directory that no longer exists.

PHP File Upload Then Show Download link

I am using the simple script below to upload a zip file via php and then unzip it on my server.
The file will be a zipped folder. When the upload is complete I want to echo a link to the new folder.
So for instance if I upload a zip file containing a folder called "bar", after the success message I want to echo "http://foo.com/bar".
Any help much appreciated.
<?php
if($_FILES["zip_file"]["name"]) {
$filename = $_FILES["zip_file"]["name"];
$source = $_FILES["zip_file"]["tmp_name"];
$type = $_FILES["zip_file"]["type"];
$name = explode(".", $filename);
$accepted_types = array('application/zip', 'application/x-zip-compressed',
'multipart/x-zip', 'application/x-compressed');
foreach($accepted_types as $mime_type) {
if($mime_type == $type) {
$okay = true;
break;
}
}
$continue = strtolower($name[1]) == 'zip' ? true : false;
if(!$continue) {
$message = "The file you are trying to upload is not a .zip file. Please try again.";
}
$target_path = "/home/var/foo.com/".$filename; // change this to the correct
site path
if(move_uploaded_file($source, $target_path)) {
$zip = new ZipArchive();
$x = $zip->open($target_path);
if ($x === true) {
$zip->extractTo("/home/var/foo.com/"); // change this to the correct site path
$zip->close();
unlink($target_path);
}
$message = "Your .zip file was uploaded and unpacked.";
} else {
$message = "There was a problem with the upload. Please try again.";
}
}
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1
/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Untitled Document</title>
</head>
<body>
<?php if($message) echo "<p>$message</p>"; ?>
<form enctype="multipart/form-data" method="post" action="">
<label>Choose a zip file to upload: <input type="file" name="zip_file" /></label>
<br />
<input type="submit" name="submit" value="Upload" />
</form>
</body>
</html>
Taking a quick glance over everything, I'd say
$message = "Your .zip file was uploaded and unpacked. Files";
from what I gather on your script your telling it to upload directly to the servers directory path of the domain. Appending $filename as the folder name to that path so it creates a folder as such accordingly. From that its hardcoding the domain like you would to any other link and then appending the same filename variable to the end of it so it shows the same folder you just uploaded to.
This is just my guess overall though again only taking a quick glance and all.
From a detailed look at your code, I would say that I can give a few comments:
1) You should use mkdir() to create a new directory in the uploads directory of your site (I assume it's the root in this case).
2) You don't need to move uploaded file before unzipping it. Simply unzip it into the newly created directory. Make sure there isn't already another directory with the same name. The uploaded file should be deleted automatically by PHP, so no need to unlink.
3) In reference to:
$name = explode(".", $filename);
What happens if the filename has more than one dot? You should really use substr() with strrpos() to get everything after the last dot.
4) After uploading, just echo the path http://www.yoursite.com/newdir - don't see the problem. If you can be more specific about what you are having difficulty with, please comment.

PHP can't upload files to server?

I have a php file that uploads images like jpegs and png onto a folder called uploads that is stored on the apache server and in the same location as the php file.
I have checked the code of both the HTML and the PHP and both seem to be perfectly fine, however whenever I try to upload a file I always get an error message and the file doesn't get uploaded.
It would be much appreciated if someone with more experience than me can look at my code and tell me why it is behaving in this manner.
Here is the HTML form:
<!--
To change this template, choose Tools | Templates
and open the template in the editor.
-->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Upload Your File</title>
</head>
<body>
<?php
// put your code here
?>
<form enctype="multipart/form-data" method="post" action="fileHandler.php">
Select File:
<input name="uploaded_file" type="file"/><br/>
<input type="submit" value="Upload"/>
</form>
</body>
</html>
and here is the PHP file that is executed when the form is submitted:
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
* PHP file that uploads files and handles any errors that may occur
* when the file is being uploaded. Then places that file into the
* "uploads" directory. File cannot work is no "uploads" directory is created in the
* same directory as the function.
*/
$fileName = $_FILES["uploaded_file"]["name"];//the files name takes from the HTML form
$fileTmpLoc = $_FILES["uploaded_file"]["tmp_name"];//file in the PHP tmp folder
$fileType = $_FILES["uploaded_file"]["type"];//the type of file
$fileSize = $_FILES["uploaded_file"]["size"];//file size in bytes
$fileErrorMsg = $FILES["uploaded_file"]["error"];//0 for false and 1 for true
$target_path = "uploads/" . basename( $_FILES["uploaded_file"]["name"]);
echo "file name: $fileName </br> temp file location: $fileTmpLoc<br/> file type: $fileType<br/> file size: $fileSize<br/> file upload target: $target_path<br/> file error msg: $fileErrorMsg<br/>";
//START PHP Image Upload Error Handling---------------------------------------------------------------------------------------------------
if(!$fileTmpLoc)//no file was chosen ie file = null
{
echo "ERROR: Please select a file before clicking submit button.";
exit();
}
else
if(!$fileSize > 16777215)//if file is > 16MB (Max size of MEDIUMBLOB)
{
echo "ERROR: Your file was larger than 16 Megabytes";
unlink($fileTmpLoc);//remove the uploaded file from the PHP folder
exit();
}
else
if(!preg_match("/\.(gif|jpg|jpeg|png)$/i", $fileName))//this codition allows only the type of files listed to be uploaded
{
echo "ERROR: Your image was not .gif, .jpg, .jpeg or .png";
unlink($fileTmpLoc);//remove the uploaded file from the PHP temp folder
exit();
}
else
if($fileErrorMsg == 1)//if file uploaded error key = 1 ie is true
{
echo "ERROR: An error occured while processing the file. Please try again.";
exit();
}
//END PHP Image Upload Error Handling---------------------------------------------------------------------------------------------------------------------
//Place it into your "uploads" folder using the move_uploaded_file() function
$moveResult = move_uploaded_file($fileTmpLoc, $target_path);
//Check to make sure the result is true before continuing
if($moveResult != true)
{
echo "ERROR: File not uploaded. Please Try again.";
unlink($fileTmpLoc);//remove the uploaded file from the PHP temp folder
}
else
{
//Display to the page so you see what is happening
echo "The file named <strong>$fileName</strong> uploaded successfully.<br/><br/>";
echo "It is <strong>$fileSize</strong> bytes.<br/><br/>";
echo "It is a <strong>$fileType</strong> type of file.<br/><br/>";
echo "The Error Message output for this upload is: $fileErrorMsg";
}
?>
make sure that the directory structure has write permissions. You can check within php by using is_writeable. By checking from within PHP you will also be making sure that the PHP user has write access.
Check the folder permissions on the server. If incorrect, you can modify your php.ini file.

Categories