Upload attachment file into another server [Mybb] - php

I'm using the latest version of mybb (mybb1.8), and it has attachment feature, but it upload the files into current host, I want upload the files to different server or host.
How can I do that ?
Download Mybb18 if you need it:
http://resources.mybb.com/downloads/mybb_1800.zip
PHP code of attachment.php file
<?php
/**
* MyBB 1.8
* Copyright 2014 MyBB Group, All Rights Reserved
*
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
*
*/
define("IN_MYBB", 1);
define('THIS_SCRIPT', 'attachment.php');
require_once "./global.php";
if($mybb->settings['enableattachments'] != 1)
{
error($lang->attachments_disabled);
}
// Find the AID we're looking for
if(isset($mybb->input['thumbnail']))
{
$aid = $mybb->get_input('thumbnail', 1);
}
else
{
$aid = $mybb->get_input('aid', 1);
}
$pid = $mybb->get_input('pid', 1);
// Select attachment data from database
if($aid)
{
$query = $db->simple_select("attachments", "*", "aid='{$aid}'");
}
else
{
$query = $db->simple_select("attachments", "*", "pid='{$pid}'");
}
$attachment = $db->fetch_array($query);
$plugins->run_hooks("attachment_start");
if(!$attachment)
{
error($lang->error_invalidattachment);
}
$pid = $attachment['pid'];
// Don't check the permissions on preview
if($pid || $attachment['uid'] != $mybb->user['uid'])
{
$post = get_post($pid);
$thread = get_thread($post['tid']);
if(!$thread && !isset($mybb->input['thumbnail']))
{
error($lang->error_invalidthread);
}
$fid = $thread['fid'];
// Get forum info
$forum = get_forum($fid);
// Permissions
$forumpermissions = forum_permissions($fid);
if($forumpermissions['canview'] == 0 || $forumpermissions['canviewthreads'] == 0 || (isset($forumpermissions['canonlyviewownthreads']) && $forumpermissions['canonlyviewownthreads'] != 0 && $thread['uid'] != $mybb->user['uid']) || ($forumpermissions['candlattachments'] == 0 && !$mybb->input['thumbnail']))
{
error_no_permission();
}
// Error if attachment is invalid or not visible
if(!$attachment['attachname'] || (!is_moderator($fid, "canviewunapprove") && ($attachment['visible'] != 1 || $thread['visible'] != 1 || $post['visible'] != 1)))
{
error($lang->error_invalidattachment);
}
}
if(!isset($mybb->input['thumbnail'])) // Only increment the download count if this is not a thumbnail
{
$attachupdate = array(
"downloads" => $attachment['downloads']+1,
);
$db->update_query("attachments", $attachupdate, "aid='{$attachment['aid']}'");
}
// basename isn't UTF-8 safe. This is a workaround.
$attachment['filename'] = ltrim(basename(' '.$attachment['filename']));
$plugins->run_hooks("attachment_end");
if(isset($mybb->input['thumbnail']))
{
$ext = get_extension($attachment['thumbnail']);
switch($ext)
{
case "gif":
$type = "image/gif";
break;
case "bmp":
$type = "image/bmp";
break;
case "png":
$type = "image/png";
break;
case "jpg":
case "jpeg":
case "jpe":
$type = "image/jpeg";
break;
default:
$type = "image/unknown";
break;
}
header("Content-disposition: filename=\"{$attachment['filename']}\"");
header("Content-type: ".$type);
$thumb = $mybb->settings['uploadspath']."/".$attachment['thumbnail'];
header("Content-length: ".#filesize($thumb));
$handle = fopen($thumb, 'rb');
while(!feof($handle))
{
echo fread($handle, 8192);
}
fclose($handle);
}
else
{
$ext = get_extension($attachment['filename']);
switch($attachment['filetype'])
{
case "application/pdf":
case "image/bmp":
case "image/gif":
case "image/jpeg":
case "image/pjpeg":
case "image/png":
case "text/plain":
header("Content-type: {$attachment['filetype']}");
$disposition = "inline";
break;
default:
$filetype = $attachment['filetype'];
if(!$filetype)
{
$filetype = 'application/force-download';
}
header("Content-type: {$filetype}");
$disposition = "attachment";
}
if(strpos(strtolower($_SERVER['HTTP_USER_AGENT']), "msie") !== false)
{
header("Content-disposition: attachment; filename=\"{$attachment['filename']}\"");
}
else
{
header("Content-disposition: {$disposition}; filename=\"{$attachment['filename']}\"");
}
if(strpos(strtolower($_SERVER['HTTP_USER_AGENT']), "msie 6.0") !== false)
{
header("Expires: -1");
}
header("Content-length: {$attachment['filesize']}");
header("Content-range: bytes=0-".($attachment['filesize']-1)."/".$attachment['filesize']);
$handle = fopen($mybb->settings['uploadspath']."/".$attachment['attachname'], 'rb');
while(!feof($handle))
{
echo fread($handle, 8192);
}
fclose($handle);
}

Firstof: a Form that posts(Data, a file) do a server it has not been called from ist considered a security risk. It is not so easy to implement so that browsers feel confident. So your recieving script should be on the same server.
That is why I would move the files after they have been posted.
I would use the command line for that if you have a linux/unix server.
You will have to copy the file from your host onto the target and delete the orginal file when successful.
Either in the filesystem(on the same server) via
system("cp filename targetdir");
or onto a different server via
system("scp filename server:targetdir")
also have a look at "rsync" which ist much more efficient when syncing files from server to server.

Related

Loading ANY Content Through PHP Script

I have this script:
<?php
$id = $_GET["id"];
switch($id)
{
default: echo "Bad ID!"; exit;
case "MyPicture1": $file = "img/img1.jpg"; break;
case "MyPicture2": $file = "img/img2.jpg"; break;
case "MyPicture3": $file = "img/img3.jpg"; break;
case "MyPicture4": $file = "img/img4.jpg"; break;
}
if(file_exists($file))
{
$size = getimagesize($file);
$fp = fopen($file, 'rb');
if($size and $fp)
{
header('Last-Modified: '.gmdate('D, d M Y H:i:s', filemtime($file)).' GMT');
header('Content-Type: '.$size['mime']);
header('Content-Length: '.filesize($file));
fpassthru($fp);
}
exit;
}
else
{
echo "Bad ID!";
}
?>
Which works fine for loading images like this <IMG Src="/Script.php?id=MyPicture1" />!
But the problem occurs when I try to load ANY other MIME content, to be displayed directly on the page or to switch page with it, but unsuccessfully... I tried with:
<?php
$file_name = $_GET["id"];
switch($file_name)
{
default: echo 'Bad ID!'; exit;
case "style1": $file_name = "csss/style_one.css"; break;
case "style2": $file_name = "csss/style_two.css"; break;
case "image1": $file_name = "images/image_one.jpg"; break;
case "image2": $file_name = "images/image_one.png"; break;
case "image3": $file_name = "images/image_one.bmp"; break;
case "image4": $file_name = "images/image_one.gif"; break;
case "video1": $file_name = "videos/video_one.avi"; break;
case "video2": $file_name = "videos/video_two.mp4"; break;
case "video3": $file_name = "videos/video_three.mov"; break;
case "php_page_1": $file_name = "php_pages/php_one.php"; break;
case "html_page_1": $file_name = "html_pages/html_one.html"; break;
case "icon_fav_1": $file_name = "icons/icon_one.ico"; break;
case "font_1": $file_name = "fonts/font_one.otf"; break;
}
if(file_exists($file_name))
{
$size = getImageSize("$file_name");
$fP = fOpen("$file_name", "rb");
if($size and $fP)
{
header('last-modified: '.gmdate('D, d M Y H:i:s', filemtime($file_name)).' GMT');
header('content-type: '.$size['mime'].');
header('content-length: '.filesize($file_name).);
fPassThru($fP);
}
exit;
}
else
{
echo 'Bad ID!';
}
?>
If I load CSS sheet like /Script.php?id=MyCSS1, I want CSS file to be loaded properly on the page - that is I want CSS file to be loaded on the page as if it was loaded with <LINK rel="stylesheet" type="text/css" href="css/styles_one.css" />. The same applies to ANY and ALL other MIME content, including switching pages with ANY extension with it - like /Script.php?id=php_page_1 (if php page 1 is clicked).
Can you help?
You can use the php function mime_content_type. Here is an example with some syntactic sugar.
<?php
$file_name = $_GET["id"];
switch($file_name)
{
default: echo 'Bad ID!'; exit;
case "style1": $file_name = "csss/style_one.css"; break;
case "style2": $file_name = "csss/style_two.css"; break;
case "image1": $file_name = "images/image_one.jpg"; break;
case "image2": $file_name = "images/image_one.png"; break;
case "image3": $file_name = "images/image_one.bmp"; break;
case "image4": $file_name = "images/image_one.gif"; break;
case "video1": $file_name = "videos/video_one.avi"; break;
case "video2": $file_name = "videos/video_two.mp4"; break;
case "video3": $file_name = "videos/video_three.mov"; break;
case "php_page_1": $file_name = "php_pages/php_one.php"; break;
case "html_page_1": $file_name = "html_pages/html_one.html"; break;
case "icon_fav_1": $file_name = "icons/icon_one.ico"; break;
case "font_1": $file_name = "fonts/font_one.otf"; break;
}
if(file_exists($file_name)) {
header("last-modified: {gmdate('D, d M Y H:i:s', filemtime($file_name))} GMT");
header("content-type: {mime_content_type($file_name)}");
header("content-length: {filesize($file_name)}");
readfile($file_name);
} else {
echo 'Bad ID!';
}
exit;
If you are using php 8. You will have to write it like this.
<?php
$file_name = $_GET["id"];
switch($file_name)
{
default: echo 'Bad ID!'; exit;
case "style1": $file_name = "csss/style_one.css"; break;
case "style2": $file_name = "csss/style_two.css"; break;
case "image1": $file_name = "images/image_one.jpg"; break;
case "image2": $file_name = "images/image_one.png"; break;
case "image3": $file_name = "images/image_one.bmp"; break;
case "image4": $file_name = "images/image_one.gif"; break;
case "video1": $file_name = "videos/video_one.avi"; break;
case "video2": $file_name = "videos/video_two.mp4"; break;
case "video3": $file_name = "videos/video_three.mov"; break;
case "php_page_1": $file_name = "php_pages/php_one.php"; break;
case "html_page_1": $file_name = "html_pages/html_one.html"; break;
case "icon_fav_1": $file_name = "icons/icon_one.ico"; break;
case "font_1": $file_name = "fonts/font_one.otf"; break;
}
if(file_exists($file_name)) {
$last_modified = gmdate('D, d M Y H:i:s', filemtime($file_name));
header("last-modified: $last_modified GMT");
$content_type = mime_content_type($file_name);
header("content-type: $content_type");
$content_length = filesize($file_name);
header("content-length: $content_length");
readfile($file_name);
} else {
echo 'Bad ID!';
}
exit;
getImageSize() is just for image files. The more general function for getting MIME types is mime_content_type().
if(file_exists($file_name))
{
$type = mime_content_type("$file_name");
$fP = fOpen("$file_name", "rb");
if($type and $fP)
{
header('last-modified: '.gmdate('D, d M Y H:i:s', filemtime($file_name)).' GMT');
header('content-type: '.$type.');
header('content-length: '.filesize($file_name).);
fPassThru($fP);
}
exit;
}
else
{
echo 'Bad ID!';
}

Shared hosting issue - no root directory access - file upload

When I tried uploading to /non_public_html/ the support team from my hosting team said that:
. Unfortunately, I have some bad news. It seems that you will not be able to move that file through a script, because of shared hosting restrictions. In order to have "www-data" permissions you would need to have a VPS package, so you could get root permissions.
So I can't upload to outside of /public_html/ it seems.
However when I try to upload to public_html it still fails, this is my code:
$PICTURE_UPLOAD_DIR = '/public_html/my_uploaded/';
$PICTURE_MIMES = [
'jpg' => 'image/jpeg',
'png' => 'image/png'
];
$image = $_FILES['image'];
$imagepath = $image['tmp_name'];
// Undefined | Multiple Files | $_FILES Corruption Attack
// If this request falls under any of them, treat it invalid.
if (!isset($image['error']) || is_array($image['error'])) {
$ojson['error'] = 'Invalid parameters'; $finish();
}
// Check $image['error'] value.
switch ($image['error']) {
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
$ojson['error'] = 'No file sent'; $finish();
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
$ojson['error'] = 'Exceeded filesize limit.'; $finish();
default:
$ojson['error'] = 'Unknown errors.'; $finish();
}
// You should also check filesize here.
$size = filesize($imagepath);
// $size = $image['size']; // dont trust $_FILES
if ($size > 1000000) {
$ojson['error'] = 'Exceeded filesize limit.'; $finish();
}
// DO NOT TRUST $_FILES['image']['mime'] VALUE !!
// Check MIME Type by yourself.
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mime = $finfo->file($imagepath);
// if ($ext = array_search($mime, $PICTURE_MIMES) === false) { // this doesnt set $ext
if (false === $ext = array_search($mime, $PICTURE_MIMES)) {
$ojson['error'] = 'Invalid file format.'; $finish();
}
$ojson['$ext'] = $ext;
$ojson['$mime'] = $mime;
// generate random file name
while (true) {
$filename = generateRandomString().'.'.$ext;
$pathtarget = $PICTURE_UPLOAD_DIR.$filename;
if (!file_exists($pathtarget)) break;
}
$ojson['$pathtarget'] = $pathtarget;
$ojson['$imagepath'] = $imagepath;
// $getimg = getimagesize($imagepath);
if(is_uploaded_file($imagepath)){
$ojson['isuploaded'] = true;
} else {
$ojson['NOTUPLOADED'] = true;
}
if(move_uploaded_file($imagepath, $pathtarget)) {
$ojson['ok move'] = 'ok';
} else {
$ojson['failed move'] = error_get_last();
}
move_uploaded_file continually fails, and error_get_last() is always printing:
move_uploaded_file(): Unable to move '/tmp/php7G5KMy' to '/public_html/my_uploaded/Q9BEsUkDre.jpg'
isuploaded is always true. I am so confused, may you please help.

class in php for thumbs

I make this code for a thumbs images.
I have MAMP with php 5.4.4 on local and this code works, but up in the server with php 5.3.19 doesn't work.
It work like
class_ethumb.php?image=demo.png&size=250
<?php
$thumb = new Thumb;
$image = $_GET['image'];
$size = $_GET['size'];
$thumb->createThumb($image,$size);
class Thumb {
public function Thumb($image)
{
//Define the Default Size
$this->defaultSize = 100;
}
// type of image example: "jpg","png" or "gif"
public function setType($image)
{
$ext = explode(".",$image);
$num = count($ext)-1;
$type = $ext[$num];
$this->type = $type;
}
// get the size of source image
public function getSize($image)
{
switch($this->type) {
case 'jpg':
$this->source = #imagecreatefromjpeg($image);
break;
case 'png':
$this->source = #imagecreatefrompng($image);
break;
case 'gif':
$this->source = #imagecreatefromgif($image);
break;
default:
die("Invalid file type");
}
$this->imgWidth = imagesx($this->source);
$this->imgHeight = imagesy($this->source);
}
public function createThumb($image,$size)
{
if(file_exists($image) === TRUE)
{
// set the type of image
$this->setType($image);
// get the original size
$this->getSize($image);
// if $size exist
if(!$size)
{
$width = $this->defaultSize;
$height = ($this->defaultSize * $this->imgHeight) / $this->imgWidth;
}
else // if not, let set defaultSize
{
$width = $size;
$height = ($size * $this->imgHeight) / $this->imgWidth;
}
// create a image from a true color
$img = imagecreatetruecolor($width,$height);
//thumb creation
ImageCopyResized($img,$this->source,0,0,0,0,$width,$height,$this->imgWidth,$this->imgHeight);
// let's print the thumb
switch($this->type) {
case 'jpg':
Header("Content-type: image/jpeg");
imageJpeg($img);
break;
case 'png':
Header("Content-type: image/png");
imagePng($img);
break;
case 'gif':
Header("Content-type: image/gif");
imageGif($img);
break;
}
}
else
{
die("File doesn't exist");
}
}
}
?>
Any help? Thanks
You should change your code so you use __construct instead of that style. You seem to be missing an argument for the constructor too. Also, you shouldn't need the ?> at the end of the file
<?php
$thumb = new Thumb();
$image = $_GET['image'];
$size = $_GET['size'];
$thumb->createThumb($image,$size);
class Thumb {
public function __construct( )
{
//Define the Default Size
$this->defaultSize = 100;
}
// ... Rest of your file
}
You could also just get rid of the constructor, and have a class variable set for defaultSize
<?php
class Thumb {
private $defaultSize = 100;
// ... Rest of file
}

Refresh in download script does not work

I have this download script which works perfectly, but one the file is downloaded, I want the page to reload. But once the file is downloaded, the page just dies? It is supposed to be a secure download script so users can't see the paths of files. It's called by using a POST submission
<?php
session_start();
//Assign variables from session
$userid = $_SESSION["id"];
$email = $_SESSION['email'];
$password = $_SESSION['password'];
//Require database connection and functions
require('includes/config.php');
include('includes/functions.php');
//Check if user is logged in
if (!$userid || !$email || !$password)
{
header("Location: index.php");
}
// Usage: Download
// Path to downloadable files (will not be revealed to users so they will never know your file's real address)
$hiddenPath = "uploaded_notes/";
// VARIABLES
if (!empty($_POST['file'])){
$file_id = $_POST['file'];
$result = mysql_query("SELECT * FROM files WHERE id='$file_id'");
$row = mysql_fetch_array($result);
$file = $row['location'];
$price = $row['price'];
$result2 = mysql_query("SELECT coins FROM users WHERE id='$userid'");
$row2 = mysql_fetch_array($result2);
$coins = $row2['coins'];
$new_coins = $coins-$price;
if ($new_coins >= 0)
{
mysql_query("UPDATE users SET coins = $new_coins WHERE id='$id'");
}
else {
header("Location: dashboard.php");
die();
}
//Insert into purchases
$datetime = date("Y-m-d H:i:s");#
mysql_query("INSERT INTO purchases (userid, fileid, datetime) VALUES ('$userid', '$file_id', '$datetime')");
$file = str_replace('%20', ' ', $file);
$category = (!empty($_GET['category'])) ? $_GET['category'] . '/' : '';
} else {
header('Location: dashboard.php');
die('Hacking attempt reported.');
}
$file_real = $hiddenPath . $category . $file;
$ip = $_SERVER['REMOTE_ADDR'];
// If requested file exists
if (file_exists($file_real)){
// Get extension of requested file
$extension = strtolower(substr(strrchr($file, "."), 1));
// Determine correct MIME type
switch($extension){
case "asf": $type = "video/x-ms-asf"; break;
case "avi": $type = "video/x-msvideo"; break;
case "exe": $type = "application/octet-stream"; break;
case "mov": $type = "video/quicktime"; break;
case "mp3": $type = "audio/mpeg"; break;
case "mpg": $type = "video/mpeg"; break;
case "mpeg": $type = "video/mpeg"; break;
case "rar": $type = "encoding/x-compress"; break;
case "txt": $type = "text/plain"; break;
case "wav": $type = "audio/wav"; break;
case "wma": $type = "audio/x-ms-wma"; break;
case "wmv": $type = "video/x-ms-wmv"; break;
case "zip": $type = "application/x-zip-compressed"; break;
case "jpg": $type = "image/jpeg"; break;
default: $type = "application/force-download"; break;
}
// Fix IE bug [0]
$header_file = (strstr($_SERVER['HTTP_USER_AGENT'], 'MSIE')) ? preg_replace('/\./', '%2e', $file, substr_count($file, '.') - 1) : $file;
// Prepare headers
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Cache-Control: public", false);
header("Content-Description: File Transfer");
header("Content-Type: " . $type);
header("Accept-Ranges: bytes");
header("Content-Disposition: attachment; filename=\"" . $header_file . "\";");
header("Content-Transfer-Encoding: binary");
header("Content-Length: " . filesize($file_real));
// Send file for download
if ($stream = fopen($file_real, 'rb')){
while(!feof($stream) && connection_status() == 0){
//reset time limit for big files
print(fread($stream,1024*8));
flush();
}
fclose($stream);
}
}else{
// Requested file does not exist (File not found)
echo("Requested file does not exist");
die();
}
?>
The refresh code works if I put it right before
print(fread($stream,1024*8));
But after that it does not work...
Downloading a file is a one time thing. You won't be able to redirect after the file is downloaded. You can try adding a refresh header before pumping out your contents, but some browsers will see that as a cancellation.
See this post for more information: https://stackoverflow.com/questions/5960895/redirect-after-download-not-working-php
You can read this post, this post, and this post for more information.
Basically, what they all boil down to is the HTTP headers. A redirect header cannot be sent after you have echoed content. On the other hand, a redirect header before echoing content will just cancel the download.
A different way you could do this would be to have a hidden iframe, and submit your request there, but I am guessing that isn't what you are wanting.

File uploaded in a folder depending on the file name and extension. Jquery/blueimp - plugin

I would kindly ask all of you if you could help me. I'm working in zend framework and I need to adjust my code so, when a user
drops the file in the browser(before the actual upload), the file name and extension is checked in a sense if it already exists. Depending on the existence of the ifle, an
icon right by the trash icon will appear (green tick if fresh upload, no other file with the same name. Red cross if there is a file).
But to address a matter that is more important to me, and that is for me to set up the code in a manner so when uploading depending on the file name and file extension, the file is being uploaded in a specific folder. So e.g. an X.png, gets into a "png" folder - subfolder "X", and Y.pdf gets into a "pdf" folder - subfolder "Y"
Here is my code do far...
This is the application.js and the jquery.fileupload-ui.js. (javascript)
http://pastebin.com/eqpK1KmX
This is the index.phtml and the layout of the index.phtml (view)
http://pastebin.com/mh5jnLju
InterfaceController.php (controller):
<?php
class Design_InterfaceController extends Zend_Controller_Action
{
public function init()
{
$this->_helper->layout()->setLayout('media');
set_include_path(implode(PATH_SEPARATOR, array(
realpath(APPLICATION_PATH . '/modules/design/models'),
realpath(APPLICATION_PATH . '/models'),
realpath(APPLICATION_PATH . '/../library'),
get_include_path(),
)));
}
public function indexAction()
{
}
public function mediaAction()
{
$this->_helper->layout()->setLayout('media');
}
public function checkFile(){
//isn't doing anything at all, just my start of thinking in a way of
//sloving this
}
function uploadjqAction()
{
$this->_helper->layout()->setLayout('media');
Zend_Loader::loadClass('Upload',
array(
APPLICATION_PATH.'/modules/design/models/vendors'
)
);
$upload_handler = new Upload();
header('Pragma: no-cache');
header('Cache-Control: private, no-cache');
header('Content-Disposition: inline; filename="files.json"');
header('X-Content-Type-Options: nosniff');
switch ($_SERVER['REQUEST_METHOD']) {
case 'HEAD':
case 'GET':
$upload_handler->get();
break;
case 'POST':
$upload_handler->post();
break;
case 'DELETE':
$upload_handler->delete();
break;
case 'OPTIONS':
break;
default:
header('HTTP/1.0 405 Method Not Allowed');
}
exit;
}
}
This is the upload.php (acting as a model):
<?php
/*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* http://creativecommons.org/licenses/MIT/
*/
error_reporting(E_ALL | E_STRICT);
class Upload
{
/* public function uploadAction() {
ini_set("max_execution_time", 10000);
$this->_helper->layout->disableLayout();
$this->_helper->viewRenderer->setNoRender(true);
if (!empty($_FILES)) {
$tempFile = $_FILES['Filedata']['tmp_name'];
$targetPath = STORAGE_PATH.'/books/' . $_POST['bookid'] . '/' . $_POST['folder'];
$targetFile = str_replace('//','/',$targetPath) . "/".$_POST['name'].".".$_POST['ext'];
if (!file_exists(str_replace('//','/',$targetPath))) mkdir(str_replace('//','/',$targetPath), 0755, true);
$result = move_uploaded_file($tempFile,$targetFile);
echo ($result)?"Success":"Fail";
}
}
*/
private $options;
function __construct($options=null) {
$this->options = array(
'script_url' => $_SERVER['PHP_SELF'],
'upload_dir' => dirname(__FILE__).'/vendors/files/',
'upload_url' => dirname($_SERVER['PHP_SELF']).'/vendors/files/',
'param_name' => 'files',
// The php.ini settings upload_max_filesize and post_max_size
// take precedence over the following max_file_size setting:
'max_file_size' => 10000000,
'min_file_size' => 1,
'accept_file_types' =>'/(\.|\/)(gif|jpeg|jpg|png|pdf)$/i',
'max_number_of_files' => null,
'discard_aborted_uploads' => true,
'image_versions' => array(
'thumbnail' => array(
'upload_dir' => dirname(__FILE__).'/vendors/thumbnails/',
'upload_url' => dirname($_SERVER['PHP_SELF']).'/vendors/thumbnails/',
'max_width' => 80,
'max_height' => 150
)
)
);
if ($options) {
$this->options = array_replace_recursive($this->options, $options);
}
}
private function get_file_object($file_name) {
$file_path = $this->options['upload_dir'].$file_name;
if (is_file($file_path) && $file_name[0] !== '.') {
$file = new stdClass();
$file->name = $file_name;
$file->size = filesize($file_path);
$file->url = $this->options['upload_url'].rawurlencode($file->name);
foreach($this->options['image_versions'] as $version => $options) {
if (is_file($options['upload_dir'].$file_name)) {
$file->{$version.'_url'} = $options['upload_url']
.rawurlencode($file->name);
}
}
$file->delete_url = $this->options['script_url']
.'?file='.rawurlencode($file->name);
$file->delete_type = 'DELETE';
return $file;
}
return null;
}
private function get_file_objects() {
return array_values(array_filter(array_map(
array($this, 'get_file_object'),
scandir($this->options['upload_dir'])
)));
}
private function create_scaled_image($file_name, $options) {
$file_path = $this->options['upload_dir'].$file_name;
$new_file_path = $options['upload_dir'].$file_name;
list($img_width, $img_height) = #getimagesize($file_path);
if (!$img_width || !$img_height) {
return false;
}
$scale = min(
$options['max_width'] / $img_width,
$options['max_height'] / $img_height
);
if ($scale > 1) {
$scale = 1;
}
$new_width = $img_width * $scale;
$new_height = $img_height * $scale;
$new_img = #imagecreatetruecolor($new_width, $new_height);
switch (strtolower(substr(strrchr($file_name, '.'), 1))) {
case 'jpg':
case 'jpeg':
$src_img = #imagecreatefromjpeg($file_path);
$write_image = 'imagejpeg';
break;
case 'gif':
#imagecolortransparent($new_img, #imagecolorallocate($new_img, 0, 0, 0));
$src_img = #imagecreatefromgif($file_path);
$write_image = 'imagegif';
break;
case 'png':
#imagecolortransparent($new_img, #imagecolorallocate($new_img, 0, 0, 0));
#imagealphablending($new_img, false);
#imagesavealpha($new_img, true);
$src_img = #imagecreatefrompng($file_path);
$write_image = 'imagepng';
break;
default:
$src_img = $image_method = null;
}
$success = $src_img && #imagecopyresampled(
$new_img,
$src_img,
0, 0, 0, 0,
$new_width,
$new_height,
$img_width,
$img_height
) && $write_image($new_img, $new_file_path);
// Free up memory (imagedestroy does not delete files):
#imagedestroy($src_img);
#imagedestroy($new_img);
return $success;
}
private function has_error($uploaded_file, $file, $error) {
if ($error) {
return $error;
}
if (!preg_match($this->options['accept_file_types'], $file->name)) {
return 'acceptFileTypes';
}
if ($uploaded_file && is_uploaded_file($uploaded_file)) {
$file_size = filesize($uploaded_file);
} else {
$file_size = $_SERVER['CONTENT_LENGTH'];
}
if ($this->options['max_file_size'] && (
$file_size > $this->options['max_file_size'] ||
$file->size > $this->options['max_file_size'])
) {
return 'maxFileSize';
}
if ($this->options['min_file_size'] &&
$file_size < $this->options['min_file_size']) {
return 'minFileSize';
}
if (is_int($this->options['max_number_of_files']) && (
count($this->get_file_objects()) >= $this->options['max_number_of_files'])
) {
return 'maxNumberOfFiles';
}
return $error;
}
private function handle_file_upload($uploaded_file, $name, $size, $type, $error) {
$file = new stdClass();
// Remove path information and dots around the filename, to prevent uploading
// into different directories or replacing hidden system files.
// Also remove control characters and spaces (\x00..\x20) around the filename:
$file->name = trim(basename(stripslashes($name)), ".\x00..\x20");
$file->size = intval($size);
$file->type = $type;
$error = $this->has_error($uploaded_file, $file, $error);
if (!$error && $file->name) {
$file_path = $this->options['upload_dir'].$file->name;
$append_file = !$this->options['discard_aborted_uploads'] &&
is_file($file_path) && $file->size > filesize($file_path);
clearstatcache();
if ($uploaded_file && is_uploaded_file($uploaded_file)) {
// multipart/formdata uploads (POST method uploads)
if ($append_file) {
file_put_contents(
$file_path,
fopen($uploaded_file, 'r'),
FILE_APPEND
);
} else {
move_uploaded_file($uploaded_file, $file_path);
}
} else {
// Non-multipart uploads (PUT method support)
file_put_contents(
$file_path,
fopen('php://input', 'r'),
$append_file ? FILE_APPEND : 0
);
}
$file_size = filesize($file_path);
if ($file_size === $file->size) {
$file->url = $this->options['upload_url'].rawurlencode($file->name);
foreach($this->options['image_versions'] as $version => $options) {
if ($this->create_scaled_image($file->name, $options)) {
$file->{$version.'_url'} = $options['upload_url']
.rawurlencode($file->name);
}
}
} else if ($this->options['discard_aborted_uploads']) {
unlink($file_path);
$file->error = 'abort';
}
$file->size = $file_size;
$file->delete_url = $this->options['script_url']
.'?file='.rawurlencode($file->name);
$file->delete_type = 'DELETE';
} else {
$file->error = $error;
}
return $file;
}
public function get() {
$file_name = isset($_REQUEST['file']) ?
basename(stripslashes($_REQUEST['file'])) : null;
if ($file_name) {
$info = $this->get_file_object($file_name);
} else {
$info = $this->get_file_objects();
}
header('Content-type: application/json');
echo json_encode($info);
}
public function post() {
$upload = isset($_FILES[$this->options['param_name']]) ?
$_FILES[$this->options['param_name']] : array(
'tmp_name' => null,
'name' => null,
'size' => null,
'type' => null,
'error' => null
);
$info = array();
if (is_array($upload['tmp_name'])) {
foreach ($upload['tmp_name'] as $index => $value) {
$info[] = $this->handle_file_upload(
$upload['tmp_name'][$index],
isset($_SERVER['HTTP_X_FILE_NAME']) ?
$_SERVER['HTTP_X_FILE_NAME'] : $upload['name'][$index],
isset($_SERVER['HTTP_X_FILE_SIZE']) ?
$_SERVER['HTTP_X_FILE_SIZE'] : $upload['size'][$index],
isset($_SERVER['HTTP_X_FILE_TYPE']) ?
$_SERVER['HTTP_X_FILE_TYPE'] : $upload['type'][$index],
$upload['error'][$index]
);
}
} else {
$info[] = $this->handle_file_upload(
$upload['tmp_name'],
isset($_SERVER['HTTP_X_FILE_NAME']) ?
$_SERVER['HTTP_X_FILE_NAME'] : $upload['name'],
isset($_SERVER['HTTP_X_FILE_SIZE']) ?
$_SERVER['HTTP_X_FILE_SIZE'] : $upload['size'],
isset($_SERVER['HTTP_X_FILE_TYPE']) ?
$_SERVER['HTTP_X_FILE_TYPE'] : $upload['type'],
$upload['error']
);
}
header('Vary: Accept');
if (isset($_SERVER['HTTP_ACCEPT']) &&
(strpos($_SERVER['HTTP_ACCEPT'], 'application/json') !== false)) {
header('Content-type: application/json');
} else {
header('Content-type: text/plain');
}
echo json_encode($info);
}
public function delete() {
$file_name = isset($_REQUEST['file']) ?
basename(stripslashes($_REQUEST['file'])) : null;
$file_path = $this->options['upload_dir'].$file_name;
$success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path);
if ($success) {
foreach($this->options['image_versions'] as $version => $options) {
$file = $options['upload_dir'].$file_name;
if (is_file($file)) {
unlink($file);
}
}
}
header('Content-type: application/json');
echo json_encode($success);
}
}
?>
If anyone is willing to help, I would be very very grateful, I know it a lot of work, I'm a noob and I need all the help I can get.
Thank you in advance! and please don't get mad at me.
A few general comments.
Typically, the include_path setting is done at Bootstrap, not in the controller.
I would clearly separate in my mind what happens on the server side and what happens on the client side.
First, think of it first as a standard form submission. The form has a file element, the user browses his file system to select his file. He clicks submit. It either succeeds or fails. All the dragging and dropping and changing icons is pure client-side candy to be added after you have the core functionality in place.
So, I would create a form that has a standard file element. To that element, I would attach a custom validator that performs your specific directory/filename checks. In the event of a valid submission, you employ a model/service that moves the file to the right place, writes your db records, etc.
Then I would layer on some AJAX handling. Client-side script intercepts the form's submit event and you use an AjaxContext action helper on the server side to send back JSON responses. These responses are handled by client-side code that renders your ok/fail icons.
Finally, I would layer on the client-side drag/drop functionality to trigger the submit event.
The benefits:
It clearly delineate server-side and client-side issues.
It breaks the overall job into a targeted collection of well-defined tasks.
Progressive enhancement/graceful degradation.
Seems more consistent with the ZF way of handling form submissions in controllers (create form with validators, check isValid(), process successful submission).
I recognize that this is only broad brush-strokes, but I hope it helps to clarify some thinking.

Categories