I'm developing an api on which it gets an image and resizes it into three sizes and zips it. I have some methods to validate the file, run the resizer class and its methods and finally give files as zip file and a link to download them. Now I have problem with content type validation and zipping. I searched a lot and I couldn't find any tutorial. I'd be thankful if you help me with my errors.
rest.php
<?php
require_once 'constants.php';
abstract class Rest
{
public array $request;
public array $errors = [];
public function __construct()
{
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
$this->throwError(REQUEST_METHODS_NOT_VALID, 'Request method is not valid.');
}
$this->request = $_FILES + $_POST;
$fileName = $_FILES['image']['name'];
$fileType = $_FILES['image']['type'];
$this->validateRequest($fileName);
if (empty($this->errors)){
$this->executeApi();
}
$this->response();
}
public abstract function validateRequest($request);
public abstract function executeApi();
public function validateParameters($fieldName, $value, $dataType, $required) {
}
public function throwError($code, $message) {
header("content-type: application/json");
$errorMsg = json_encode(['error'=>['status'=>$code, 'message'=>$message]]);
echo $errorMsg;
exit();
}
public function response() {
//???
}
}
api.php
<?php
require_once 'image-resizer.php';
class Api extends Rest
{
public function validateRequest($request)
{
// if ($request !== 'image/jpeg') {
if ($_SERVER['CONTENT_TYPE'] !== 'image/jpeg') {
$this->throwError(REQUEST_CONTENT_TYPE_NOT_VALID, 'Request content type is not valid.');
$errors = json_encode(array("message" => "Request content type is not valid.", "status" => false));
echo $errors;
}
json_decode($request, true);
}
public function executeApi()
{
$source = $this->request['image'];
$resize = new Resizer();
$resize->imageResizer($source);
}
}
getimagesize is not to be used to validate a file as image
$imgsize = getimagesize($sourceFile);
$srcWidth = $imgsize[0];
$srcHeight = $imgsize[1];
$mime = $imgsize['mime'];
you can use: fileinfo
OR you may validate extension using pathinfo
$allowedExt = ['jpg', 'jpeg', 'png'];
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
if (!in_array($ext, $allowedExt)) {
return FALSE;
}
// filesize validation
if (filesize($tmpName) > MAX_FILE_SIZE) {
}
check more on filesize
Edit:
You may check this link for zipping files with PHP
EDIT:
$this->request = $_FILES + $_POST; // this is insecure way to get the data
check $_POST data sanitization
what is a good method to sanitize the whole $_POST array in php?
Related
<?php
class Mail{
private $image_box;
public $count = 0;
public $zipper;
$encoding = "base64";
$type = "image/png";
public function __construct(){
$this->turnToImage();
}
public function addToObject($object_name, $object_data){
//save to object
// $object_name : $object_data
}
public function turnToImage(){
$this->image_box = $_POST['canvas_data'];
foreach($this->image_box as $img)
{
$this->count++;
$data = substr($img, strpos($img, ","));
$image_name ="OrderImg".$this->count.".png";
$this->addToObject($image_name, $data);
}
}
public function toZip(){
}
}
$Mail = new Mail();
?>
i have canvas fabric image data , and i want to decode to image and zip it up and send by mail.
so 1st question is how do i save the my data to object and be like this ?
object{
$object_name1 : object_data1,
$object_name2 : object_data2
}
2nd how do i zip them up ? after i store to object and some how zip them up together as one zip file ? i am stucked here.
I'm having trouble moving uploaded files, the problem seems to be a permissions problem, any help would be much appreciated. I'm using windows 10 and I've change my temp folder in php.ini to a custom folder in xampp directory and when I check this temp folder the file isn't there either, so it seems that it isn't even being uploaded to them temp. Please help.
class PortfolioItem extends DataBaseCommonObj{
protected static $table_name = 'portfolio_item';
protected static $db_fields = array('id','filename','mimetype','size','caption','job_id');
public $id;
public $filename;
public $mimetype;
public $size;
public $caption;
public $job_id;
private $temp_path;
protected $upload_dir="_portfolio-items";
public $errors=array();
protected $upload_errors = array(
// http://www.php.net/manual/en/features.file-upload.errors.php
UPLOAD_ERR_OK => "No errors.",
UPLOAD_ERR_INI_SIZE => "Larger than upload_max_filesize.",
UPLOAD_ERR_FORM_SIZE => "Larger than form MAX_FILE_SIZE.",
UPLOAD_ERR_PARTIAL => "Partial upload.",
UPLOAD_ERR_NO_FILE => "No file.",
UPLOAD_ERR_NO_TMP_DIR => "No temporary directory.",
UPLOAD_ERR_CANT_WRITE => "Can't write to disk.",
UPLOAD_ERR_EXTENSION => "File upload stopped by extension."
);
public function attach_file($file){
global $session;
if(!$file || empty($file) || !is_array($file)){
$this->errors[] = 'no file was uploaded';
return false;
}elseif ($file['error'] != 0) {
$this->errors[]=$this->upload_errors[$file['error']];
return false;
}else {
$this->filename = basename($file['name']);
$this->temp_path = $file['tmp_name'];
$this->mimetype = $file['type'];
$this->size = $file['size'];
if(isset($session->message) && $session->message !== ''){
$current_job = Job::find_by_id(intval($session->message));
$this->job_id = $current_job->id;
}
return true;
}
}
defined('DS')?null:define('DS',DIRECTORY_SEPARATOR);
defined('SITE_ROOT')?null:define('SITE_ROOT', DS.'mp_creations');
defined('INC_PATH')?null:define('INC_PATH', SITE_ROOT.DS.'includes');
defined('PUB_PATH')?null:define('PUB_PATH', SITE_ROOT.DS.'public');
public function save(){
if(isset($this->id)){
$this->update();
}else{
if(!empty($this->errors)){
return false;
}
if(empty($this->filename) || empty($this->temp_path)){
$this->errors[] = 'file path not available';
return false;
}
$target_path = PUB_PATH.DS.$this->upload_dir.DS.$this->filename;
if(file_exists($target_path)){
$this->errors[] = "the file {$this->filename} already exists";
return false;
}
if(move_uploaded_file($this->temp_path,$target_path)){
if($this->create()){
unset($this->temp_path);
return true;
}
}else {
$this->errors[]='The file upload failed, possibly due to permission issues';
return false;
}
}
}
The file will be deleted from the temporary directory at the end of the request if it has not been moved away or renamed.
http://php.net/manual/en/features.file-upload.post-method.php
The problem seemed to have been my methods and not anything to do with permissions. I was was using values stored in the session to pass to the move_uploaded_file() function, once I did it directly from the POST request it worked fine. Is it that the move_uploaded_file() needs to be called from a POST request? Anybody care to shed some light on this, please do as I'd love to learn what happening behind the scenes.
**check_imgupload.class.php**
<?php
class Image extends Connection
{
private $img_name;
private $img_extension;
private $img_size;
private $tmp_name;
private $target_dir;
//getter and setters
public function getadmin_img()
{
$this->img;
}
public function setadmin_img($img='')
{
$this->img=$img;
}
public function getimg_name()
{
$this->img_name;
}
public function setimg_name($imgn='')
{
$this->img_name=$imgn;
}
public function setimg_size($size='')
{
$this->img_size=$size;
}
public function setimg_type($imgty='')
{
$this->img_type=$imgty;
}
public function settmp_img_name($tmpimg='')
{
$this->img_tmp=$tmpimg;
}
public function check_img()
{
if(isset($this->img)){
$errors= array();
//$file_name = $_FILES['image']['name'];
//$file_size =$_FILES['image']['size'];
//$file_tmp =$_FILES['image']['tmp_name'];
//$file_type=$_FILES['image']['type'];
$file_ext=strtolower(end(explode('.',$this->img_name)));
$expensions= array("jpeg","jpg","png","PNG","bmp","Gif");
$target_dir='../Uploads';
if(in_array($file_ext,$expensions)=== false){
$errors[]="extension not allowed, please choose a JPEG or PNG file.";
}
else if($this->img_size> 2097152){
$errors[]='File size must be excately 2 MB';
}
else if(file_exists($target_dir.'/'.$this->img_name))
{
$errors[]='File already exists..';
}
else if(empty($errors)==true){
move_uploaded_file($this->img_tmp,"$target_dir/$this->img_name");
return true;
}
else{
return $errors;
}
}
}
}
**Process_add_user.php**
<?php
session_start();
//load classes
require_once('../classes/db-connection.class.php');
require_once('../classes/user.class.php');
require_once('../classes/locate.class.php');
require_once('../classes/check_img.class.php');
//create an object
$objImage= new Image();
//
//setting the inputs
$admin_img=$_FILES['admin_img'];
$admin_img_name=mysqli_real_escape_string($objImage->conxn,$_FILES['admin_img']['name']);
$size=mysqli_real_escape_string($objImage->conxn,$_FILES['admin_img']['size']);
$type=mysqli_real_escape_string($objImage->conxn,$_FILES['admin_img']['type']);
$tmp_name=mysqli_real_escape_string($objImage->conxn,$_FILES['admin_img']['tmp_name']);
$objImage->setadmin_img($admin_img);
$objImage->setimg_name($admin_img_name);
$objImage->setimg_size($size);
$objImage->setimg_type($type);
$objImage->settmp_img_name($tmp_name);
//check the image extension
$img_return=$objImage->check_img();
//now teh condition for flag
if($img_return==true)
{
$objUser=new User();
$admin_name=mysqli_real_escape_string($objUser->conxn,$_POST['admin_name']);
$admin_email=mysqli_real_escape_string($objUser->conxn,$_POST['admin_email']);
$admin_password=mysqli_real_escape_string($objUser->conxn,$_POST['admin_password']);
$admin_password2=mysqli_real_escape_string($objUser->conxn,$_POST['admin_password2']);
$admin_access_level=mysqli_real_escape_string($objUser->conxn,$_POST['admin_access_level']);
$objUser->setAdmin_username($admin_name);
$objUser->setPassword($admin_password);
$objUser->setAdmin_email($admin_email);
$objUser->setaccess_level($admin_access_level);
$flag=$objUser->addadmin();
}
elseif($img_return==$errors)
echo $img_return;
//Errorrs are not shown
//new locate('../index.php?error='.base64_encode());
else
new locate('../../index');
I Have checked for image before upload when the check_img()function return true image is uploaded and its all right and when the $errors is returned i want to show the same error returned as $errors.
echo $errors is not working.
To show an array you can var_dump() or print_r()
Try this...
if(isset($this->img)){
...any of this stuff...
}
else{
return $errors;
print_r($errors);
}
}
}
That should do it.
NOTE: I strongly advise against this for error handling. The output to the page is ugly and just not a user friendly or graceful way to handle errors.
I am developing a file uploaded class, and trying to perform few validation before other codes, but its returning all vars instead of false, check following code....
class FileUploader
{
private $filePath;
function __construct($file_path) {
if(file_exists($file_path)) {
$this->filePath = $file_path;
}
else return false;
}
}
When I am using this class like following....
$file_path = getcwd().'\img.pn'; //invalid path
$file_uploader = new FileUploader($file_path);
if($file_uploader) {
//process
}
else {
echo 'Invalid File Path!';
}
But it doesn't echo Invalid File Path as expected, when i tried var_dump, it returned following output...
object(FileUploader)[1]
private 'filePath' => null
Please help to fix this. thanks.
You might consider using an exception in the constructor as constructors should no return anything. (Have a look at this question).
Otherwise you may create a function to check the file_path :
class FileUploader
{
private $filePath;
function __construct($file_path) {
$this->filePath = $file_path;
}
function isValidFilePath() {
return file_exists($this->file_path);
}
}
and then :
$file_path = getcwd().'\img.pn'; //invalid path
$file_uploader = new FileUploader($file_path);
if($file_uploader->isValidFilePath()) {
//process
}
else {
echo 'Invalid File Path!';
}
If a user uploads a file and the contents are retrieved like so
$file = $_FILES['uploadedFile'];
Then, the file is sent to a function to make sure it's an accepted file type. If it is, save it on the server
function saveInputFile($file){
if($check->checkFile($file)== TRUE){
//save $file on my server
}
else{
echo "can't be saved!";
}
}
Assuming it passes the checkFile function, how can I then save this file to my server from within the saveInputFile function? Can I set the file equal to a variable, and then save that variable or do I have to save the file directly from the POST data?
I've seen it done like this, but I already have the file passed into this function.
if(move_uploaded_file($_FILES['uploadedfile']['tmp_name'], $target_path)) {
echo "The file ". basename( $_FILES['uploadedfile']['name']). " has been uploaded";
} else{
echo "There was an error uploading the file, please try again!";
}
When it comes down to it, I want to save a file in the following function. Can I pass the file like a variable as I did in the saveInputFile function above, or does it not work like this?
You can make the upload file a type of it's own that has the methods it needs next to it's data. That will make the usage more flexible:
$upload = new UploadFile($_FILES['uploadedFile']);
$message = saveInputFile($upload);
echo $message;
function saveInputFile(UploadFile $upload)
{
if ($check->checkFile($upload->getBasename()) == TRUE) {
$message = $upload->moveTo($target_path)
? sprintf('The file %s has been uploaded', $upload->getBasename())
: 'There was an error uploading the file, please try again!'
;
} else {
$message = "can't be saved!";
}
return $message;
}
The new type UploadFile represents one file from the the $_FILE array, it is a class that wraps the basic data and methods a file-upload carries. Here is some example code:
class UploadFile
{
protected $file;
private $filename;
public function __construct(array $file)
{
$this->file = $file;
}
public function hasError()
{
return $this->getProperty('error') !== UPLOAD_ERR_OK;
}
public function getError()
{
return $this->getProperty('error');
}
public function getBasename()
{
return basename($this->getProperty('name'));
}
public function getFilename()
{
return $this->filename;
}
/**
* #param $newName
* #return NULL|SplFileInfo
* #throws BadMethodCallException
*/
public function moveTo($newName)
{
$newName = (string)$newName;
$filename = $this->getFilename();
if ($filename !== NULL) {
throw new BadMethodCallException(sprintf('Upload file (%s) has been already moved (%s).', $this->getBasename(), $filename));
}
$tmpName = $this->getProperty('tmp_name');
if (move_uploaded_file($tmpName, $newName)) {
$this->filename = realpath($newName);
}
return $this->getFileInfo();
}
/**
* #return SplFileInfo|NULL
*/
public function getFileInfo()
{
$filename = $this->getFilename();
if ($filename !== NULL) {
return new SplFileInfo($filename);
}
}
protected function getProperty($name, $default = NULL)
{
if (isset($this->file[$name])) {
return $this->file[$name];
}
return $default;
}
}
Use it at your will. See as well SplFileInfo and the documentation about file uploads in the PHP manual which documents the structure of the $_FILE array and the PHP upload error codes (which are important).
Your move_uploaded_file function should take 2 parameters, the source file name and the destination file name.
In PHP the file move function is called rename.