PEEL Shopping
Open source ecommerce : PEEL Shopping
FineUploader.php
Go to the documentation of this file.
1 <?php
2 
3 class FineUploader {
4 
5  public $allowedExtensions = array();
6  public $sizeLimit = null;
7  public $inputName = 'qqfile';
8  public $chunksFolder = 'chunks';
9 
10  public $chunksCleanupProbability = 0.001; // Once in 1000 requests on avg
11  public $chunksExpireIn = 604800; // One week
12 
13  protected $uploadName;
14 
15  function __construct(){
16  $this->sizeLimit = min($this->toBytes(ini_get('upload_max_filesize')), $this->toBytes(ini_get('post_max_size')));
17  }
18 
22  public function getName(){
23  if (isset($_REQUEST['qqfilename']))
24  return $_REQUEST['qqfilename'];
25 
26  if (isset($_FILES[$this->inputName]))
27  return $_FILES[$this->inputName]['name'];
28  }
29 
33  public function getUploadName(){
34  return $this->uploadName;
35  }
36 
42  public function handleUpload($uploadDirectory, $name = null){
43 
44  if (is_writable($this->chunksFolder) &&
45  1 == mt_rand(1, 1/$this->chunksCleanupProbability)){
46 
47  // Run garbage collection
48  $this->cleanupChunks();
49  }
50 
51  // Check that the max upload size specified in class configuration does not
52  // exceed size allowed by server config
53  if ($this->toBytes(ini_get('post_max_size')) < $this->sizeLimit ||
54  $this->toBytes(ini_get('upload_max_filesize')) < $this->sizeLimit){
55  $size = max(1, $this->sizeLimit / 1024 / 1024) . 'M';
56  return array('error'=>"Server error. Increase post_max_size and upload_max_filesize to ".$size);
57  }
58 
59  if (!is_writable($uploadDirectory)){
60  return array('error' => sprintf($GLOBALS["STR_ADMIN_INSTALL_DIRECTORY_NOK"], $uploadDirectory));
61  }
62 
63  if(!isset($_SERVER['CONTENT_TYPE'])) {
64  return array('error' => "No files were uploaded.");
65  } else if (strpos(strtolower($_SERVER['CONTENT_TYPE']), 'multipart/') !== 0){
66  return array('error' => "Server error. Not a multipart request. Please set forceMultipart to default value (true).");
67  }
68 
69  // Get size and name
70 
71  $file = vb($_FILES[$this->inputName]);
72  $size = vb($file['size']);
73 
74  if ($name === null){
75  $name = $this->getName();
76  }
77 
78  // Validate name
79 
80  if ($name === null || $name === ''){
81  return array('error' => 'File name empty.');
82  }
83 
84  // Validate file size
85 
86  if ($size == 0){
87  return array('error' => $GLOBALS["STR_FILE_EMPTY"]);
88  }
89 
90  if ($size > $this->sizeLimit){
91  return array('error' => 'File is too large.');
92  }
93 
94  // Validate file extension
95 
96  $pathinfo = pathinfo($name);
97  $ext = isset($pathinfo['extension']) ? $pathinfo['extension'] : '';
98 
99  if($this->allowedExtensions && !in_array(strtolower($ext), array_map("strtolower", $this->allowedExtensions))){
100  $these = implode(', ', $this->allowedExtensions);
101  return array('error' => 'File has an invalid extension, it should be one of '. $these . '.');
102  }
103 
104  // Save a chunk
105 
106  $totalParts = isset($_REQUEST['qqtotalparts']) ? (int)$_REQUEST['qqtotalparts'] : 1;
107 
108  if ($totalParts > 1){
109 
111  $partIndex = (int)$_REQUEST['qqpartindex'];
112  $uuid = $_REQUEST['qquuid'];
113 
114  if (!is_writable($chunksFolder) || !is_executable($uploadDirectory)){
115  return array('error' => "Server error. Chunks directory isn't writable or executable.");
116  }
117 
118  $targetFolder = $this->chunksFolder.DIRECTORY_SEPARATOR.$uuid;
119 
120  if (!file_exists($targetFolder)){
121  mkdir($targetFolder);
122  }
123 
124  $target = $targetFolder.'/'.$partIndex;
125  $success = move_uploaded_file($_FILES[$this->inputName]['tmp_name'], $target);
126 
127  // Last chunk saved successfully
128  if ($success AND ($totalParts-1 == $partIndex)){
129 
130  $target = $this->getUniqueTargetPath($uploadDirectory, $name);
131  $this->uploadName = basename($target);
132 
133  $target = fopen($target, 'w');
134 
135  for ($i=0; $i<$totalParts; $i++){
136  $chunk = fopen($targetFolder.'/'.$i, "rb");
137  stream_copy_to_stream($chunk, $target);
138  fclose($chunk);
139  }
140 
141  // Success
142  fclose($target);
143 
144  for ($i=0; $i<$totalParts; $i++){
145  $chunk = fopen($targetFolder.'/'.$i, "r");
146  unlink($targetFolder.'/'.$i);
147  }
148 
149  rmdir($targetFolder);
150 
151  return array("success" => true);
152 
153  }
154 
155  return array("success" => true);
156 
157  } else {
158 
159  $target = $this->getUniqueTargetPath($uploadDirectory, $name);
160 
161  if ($target){
162  $this->uploadName = basename($target);
163 
164  if (move_uploaded_file($file['tmp_name'], $target)){
165  return array('success'=> true);
166  }
167  }
168 
169  return array('error'=> 'Could not save uploaded file.' .
170  'The upload was cancelled, or server error encountered');
171  }
172  }
173 
180  protected function getUniqueTargetPath($uploadDirectory, $filename)
181  {
182  // Allow only one process at the time to get a unique file name, otherwise
183  // if multiple people would upload a file with the same name at the same time
184  // only the latest would be saved.
185 
186  if (function_exists('sem_acquire')){
187  $lock = sem_get(ftok(__FILE__, 'u'));
188  sem_acquire($lock);
189  }
190 
191  $pathinfo = pathinfo($filename);
192  $base = $pathinfo['filename'];
193  $ext = isset($pathinfo['extension']) ? $pathinfo['extension'] : '';
194  $ext = $ext == '' ? $ext : '.' . $ext;
195 
196  $unique = $base;
197  $suffix = 0;
198 
199  // Get unique file name for the file, by appending random suffix.
200 
201  while (file_exists($uploadDirectory . DIRECTORY_SEPARATOR . $unique . $ext)){
202  $suffix += rand(1, 999);
203  $unique = $base.'-'.$suffix;
204  }
205 
206  $result = $uploadDirectory . DIRECTORY_SEPARATOR . $unique . $ext;
207 
208  // Create an empty target file
209  if (!touch($result)){
210  // Failed
211  $result = false;
212  }
213 
214  if (function_exists('sem_acquire')){
215  sem_release($lock);
216  }
217 
218  return $result;
219  }
220 
225  protected function cleanupChunks(){
226  foreach (scandir($this->chunksFolder) as $item){
227  if ($item == "." || $item == "..")
228  continue;
229 
230  $path = $this->chunksFolder.DIRECTORY_SEPARATOR.$item;
231 
232  if (!is_dir($path))
233  continue;
234 
235  if (time() - filemtime($path) > $this->chunksExpireIn){
236  $this->removeDir($path);
237  }
238  }
239  }
240 
245  protected function removeDir($dir){
246  foreach (scandir($dir) as $item){
247  if ($item == "." || $item == "..")
248  continue;
249 
250  unlink($dir.DIRECTORY_SEPARATOR.$item);
251  }
252  rmdir($dir);
253  }
254 
259  function toBytes($str){
260  $val = trim($str);
261  $last = strtolower($str[strlen($str)-1]);
262  switch($last) {
263  case 'g': $val *= 1024;
264  case 'm': $val *= 1024;
265  case 'k': $val *= 1024;
266  }
267  return $val;
268  }
269 }
removeDir($dir)
Removes a directory and all files contained inside.
$result
vb(&$var, $default=null)
Variable blanche if $var n'est pas défini, retourne $default, sinon retourne $var.
Definition: format.php:97
getUploadName()
Get the name of the uploaded file.
getUniqueTargetPath($uploadDirectory, $filename)
Returns a path to use with this upload.
cleanupChunks()
Deletes all file parts in the chunks folder for files uploaded more than chunksExpireIn seconds ago...
$uploader inputName
$uploader chunksFolder
handleUpload($uploadDirectory, $name=null)
Process the upload.
$GLOBALS['page_columns_count']
$filename
toBytes($str)
Converts a given size with units to bytes.
getName()
Get the original filename.
if(!empty($GLOBALS['site_parameters']['extensions_valides_'.$file_kind])) $uploader sizeLimit

This documentation for Open ecommerce PEEL Shopping and PEEL.fr has been generated by Doxygen on Thu Oct 15 2015 14:29:56 - Peel ecommerce is a product of Agence web Advisto SAS. All rights reserved.