Skip to content

Commit 13e86f5

Browse files
committed
php traditional code has moved
1 parent 6d1e313 commit 13e86f5

File tree

1 file changed

+2
-352
lines changed

1 file changed

+2
-352
lines changed

php/traditional/handler.php

Lines changed: 2 additions & 352 deletions
Original file line numberDiff line numberDiff line change
@@ -1,352 +1,2 @@
1-
<?php
2-
3-
/**
4-
* Do not use or reference this directly from your client-side code.
5-
* Instead, this should be required via the endpoint.php or endpoint-cors.php
6-
* file(s).
7-
*/
8-
9-
class UploadHandler {
10-
11-
public $allowedExtensions = array();
12-
public $sizeLimit = null;
13-
public $inputName = 'qqfile';
14-
public $chunksFolder = 'chunks';
15-
16-
public $chunksCleanupProbability = 0.001; // Once in 1000 requests on avg
17-
public $chunksExpireIn = 604800; // One week
18-
19-
protected $uploadName;
20-
21-
function __construct(){
22-
$this->sizeLimit = $this->toBytes(ini_get('upload_max_filesize'));
23-
}
24-
25-
/**
26-
* Get the original filename
27-
*/
28-
public function getName(){
29-
if (isset($_REQUEST['qqfilename']))
30-
return $_REQUEST['qqfilename'];
31-
32-
if (isset($_FILES[$this->inputName]))
33-
return $_FILES[$this->inputName]['name'];
34-
}
35-
36-
/**
37-
* Get the name of the uploaded file
38-
*/
39-
public function getUploadName(){
40-
return $this->uploadName;
41-
}
42-
43-
public function combineChunks($uploadDirectory) {
44-
$uuid = $_POST['qquuid'];
45-
$name = $this->getName();
46-
$targetFolder = $this->chunksFolder.DIRECTORY_SEPARATOR.$uuid;
47-
$totalParts = isset($_REQUEST['qqtotalparts']) ? (int)$_REQUEST['qqtotalparts'] : 1;
48-
49-
$target = join(DIRECTORY_SEPARATOR, array($uploadDirectory, $uuid, $name));
50-
$this->uploadName = $name;
51-
52-
if (!file_exists($target)){
53-
mkdir(dirname($target));
54-
}
55-
$target = fopen($target, 'wb');
56-
57-
for ($i=0; $i<$totalParts; $i++){
58-
$chunk = fopen($targetFolder.DIRECTORY_SEPARATOR.$i, "rb");
59-
stream_copy_to_stream($chunk, $target);
60-
fclose($chunk);
61-
}
62-
63-
// Success
64-
fclose($target);
65-
66-
for ($i=0; $i<$totalParts; $i++){
67-
unlink($targetFolder.DIRECTORY_SEPARATOR.$i);
68-
}
69-
70-
rmdir($targetFolder);
71-
72-
return array("success" => true, "uuid" => $uuid);
73-
}
74-
75-
/**
76-
* Process the upload.
77-
* @param string $uploadDirectory Target directory.
78-
* @param string $name Overwrites the name of the file.
79-
*/
80-
public function handleUpload($uploadDirectory, $name = null){
81-
82-
if (is_writable($this->chunksFolder) &&
83-
1 == mt_rand(1, 1/$this->chunksCleanupProbability)){
84-
85-
// Run garbage collection
86-
$this->cleanupChunks();
87-
}
88-
89-
// Check that the max upload size specified in class configuration does not
90-
// exceed size allowed by server config
91-
if ($this->toBytes(ini_get('post_max_size')) < $this->sizeLimit ||
92-
$this->toBytes(ini_get('upload_max_filesize')) < $this->sizeLimit){
93-
$size = max(1, $this->sizeLimit / 1024 / 1024) . 'M';
94-
return array('error'=>"Server error. Increase post_max_size and upload_max_filesize to ".$size);
95-
}
96-
97-
if ($this->isInaccessible($uploadDirectory)){
98-
return array('error' => "Server error. Uploads directory isn't writable");
99-
}
100-
101-
$type = $_SERVER['CONTENT_TYPE'];
102-
if (isset($_SERVER['HTTP_CONTENT_TYPE'])) {
103-
$type = $_SERVER['HTTP_CONTENT_TYPE'];
104-
}
105-
106-
if(!isset($type)) {
107-
return array('error' => "No files were uploaded.");
108-
} else if (strpos(strtolower($type), 'multipart/') !== 0){
109-
return array('error' => "Server error. Not a multipart request. Please set forceMultipart to default value (true).");
110-
}
111-
112-
// Get size and name
113-
$file = $_FILES[$this->inputName];
114-
$size = $file['size'];
115-
116-
if ($name === null){
117-
$name = $this->getName();
118-
}
119-
120-
// Validate name
121-
if ($name === null || $name === ''){
122-
return array('error' => 'File name empty.');
123-
}
124-
125-
// Validate file size
126-
if ($size == 0){
127-
return array('error' => 'File is empty.');
128-
}
129-
130-
if ($size > $this->sizeLimit){
131-
return array('error' => 'File is too large.');
132-
}
133-
134-
// Validate file extension
135-
$pathinfo = pathinfo($name);
136-
$ext = isset($pathinfo['extension']) ? $pathinfo['extension'] : '';
137-
138-
if($this->allowedExtensions && !in_array(strtolower($ext), array_map("strtolower", $this->allowedExtensions))){
139-
$these = implode(', ', $this->allowedExtensions);
140-
return array('error' => 'File has an invalid extension, it should be one of '. $these . '.');
141-
}
142-
143-
// Save a chunk
144-
$totalParts = isset($_REQUEST['qqtotalparts']) ? (int)$_REQUEST['qqtotalparts'] : 1;
145-
146-
$uuid = $_REQUEST['qquuid'];
147-
if ($totalParts > 1){
148-
# chunked upload
149-
150-
$chunksFolder = $this->chunksFolder;
151-
$partIndex = (int)$_REQUEST['qqpartindex'];
152-
153-
if (!is_writable($chunksFolder) && !is_executable($uploadDirectory)){
154-
return array('error' => "Server error. Chunks directory isn't writable or executable.");
155-
}
156-
157-
$targetFolder = $this->chunksFolder.DIRECTORY_SEPARATOR.$uuid;
158-
159-
if (!file_exists($targetFolder)){
160-
mkdir($targetFolder);
161-
}
162-
163-
$target = $targetFolder.'/'.$partIndex;
164-
$success = move_uploaded_file($_FILES[$this->inputName]['tmp_name'], $target);
165-
166-
return array("success" => true, "uuid" => $uuid);
167-
168-
}
169-
else {
170-
# non-chunked upload
171-
172-
$target = join(DIRECTORY_SEPARATOR, array($uploadDirectory, $uuid, $name));
173-
//$target = $this->getUniqueTargetPath($uploadDirectory, $name);
174-
175-
if ($target){
176-
$this->uploadName = basename($target);
177-
178-
if (!is_dir(dirname($target))){
179-
mkdir(dirname($target));
180-
}
181-
if (move_uploaded_file($file['tmp_name'], $target)){
182-
return array('success'=> true, "uuid" => $uuid);
183-
}
184-
}
185-
186-
return array('error'=> 'Could not save uploaded file.' .
187-
'The upload was cancelled, or server error encountered');
188-
}
189-
}
190-
191-
/**
192-
* Process a delete.
193-
* @param string $uploadDirectory Target directory.
194-
* @params string $name Overwrites the name of the file.
195-
*
196-
*/
197-
public function handleDelete($uploadDirectory, $name=null)
198-
{
199-
if ($this->isInaccessible($uploadDirectory)) {
200-
return array('error' => "Server error. Uploads directory isn't writable" . ((!$this->isWindows()) ? " or executable." : "."));
201-
}
202-
203-
$targetFolder = $uploadDirectory;
204-
$url = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
205-
$tokens = explode('/', $url);
206-
$uuid = $tokens[sizeof($tokens)-1];
207-
208-
$target = join(DIRECTORY_SEPARATOR, array($targetFolder, $uuid));
209-
210-
// print_r($target);
211-
if (is_dir($target)){
212-
$this->removeDir($target);
213-
return array("success" => true, "uuid" => $uuid);
214-
} else {
215-
return array("success" => false,
216-
"error" => "File not found! Unable to delete.".$url,
217-
"path" => $uuid
218-
);
219-
}
220-
221-
}
222-
223-
/**
224-
* Returns a path to use with this upload. Check that the name does not exist,
225-
* and appends a suffix otherwise.
226-
* @param string $uploadDirectory Target directory
227-
* @param string $filename The name of the file to use.
228-
*/
229-
protected function getUniqueTargetPath($uploadDirectory, $filename)
230-
{
231-
// Allow only one process at the time to get a unique file name, otherwise
232-
// if multiple people would upload a file with the same name at the same time
233-
// only the latest would be saved.
234-
235-
if (function_exists('sem_acquire')){
236-
$lock = sem_get(ftok(__FILE__, 'u'));
237-
sem_acquire($lock);
238-
}
239-
240-
$pathinfo = pathinfo($filename);
241-
$base = $pathinfo['filename'];
242-
$ext = isset($pathinfo['extension']) ? $pathinfo['extension'] : '';
243-
$ext = $ext == '' ? $ext : '.' . $ext;
244-
245-
$unique = $base;
246-
$suffix = 0;
247-
248-
// Get unique file name for the file, by appending random suffix.
249-
250-
while (file_exists($uploadDirectory . DIRECTORY_SEPARATOR . $unique . $ext)){
251-
$suffix += rand(1, 999);
252-
$unique = $base.'-'.$suffix;
253-
}
254-
255-
$result = $uploadDirectory . DIRECTORY_SEPARATOR . $unique . $ext;
256-
257-
// Create an empty target file
258-
if (!touch($result)){
259-
// Failed
260-
$result = false;
261-
}
262-
263-
if (function_exists('sem_acquire')){
264-
sem_release($lock);
265-
}
266-
267-
return $result;
268-
}
269-
270-
/**
271-
* Deletes all file parts in the chunks folder for files uploaded
272-
* more than chunksExpireIn seconds ago
273-
*/
274-
protected function cleanupChunks(){
275-
foreach (scandir($this->chunksFolder) as $item){
276-
if ($item == "." || $item == "..")
277-
continue;
278-
279-
$path = $this->chunksFolder.DIRECTORY_SEPARATOR.$item;
280-
281-
if (!is_dir($path))
282-
continue;
283-
284-
if (time() - filemtime($path) > $this->chunksExpireIn){
285-
$this->removeDir($path);
286-
}
287-
}
288-
}
289-
290-
/**
291-
* Removes a directory and all files contained inside
292-
* @param string $dir
293-
*/
294-
protected function removeDir($dir){
295-
foreach (scandir($dir) as $item){
296-
if ($item == "." || $item == "..")
297-
continue;
298-
299-
if (is_dir($item)){
300-
$this->removeDir($item);
301-
} else {
302-
unlink(join(DIRECTORY_SEPARATOR, array($dir, $item)));
303-
}
304-
305-
}
306-
rmdir($dir);
307-
}
308-
309-
/**
310-
* Converts a given size with units to bytes.
311-
* @param string $str
312-
*/
313-
protected function toBytes($str){
314-
$val = trim($str);
315-
$last = strtolower($str[strlen($str)-1]);
316-
switch($last) {
317-
case 'g': $val *= 1024;
318-
case 'm': $val *= 1024;
319-
case 'k': $val *= 1024;
320-
}
321-
return $val;
322-
}
323-
324-
/**
325-
* Determines whether a directory can be accessed.
326-
*
327-
* is_executable() is not reliable on Windows prior PHP 5.0.0
328-
* (http://www.php.net/manual/en/function.is-executable.php)
329-
* The following tests if the current OS is Windows and if so, merely
330-
* checks if the folder is writable;
331-
* otherwise, it checks additionally for executable status (like before).
332-
*
333-
* @param string $directory The target directory to test access
334-
*/
335-
protected function isInaccessible($directory) {
336-
$isWin = $this->isWindows();
337-
$folderInaccessible = ($isWin) ? !is_writable($directory) : ( !is_writable($directory) && !is_executable($directory) );
338-
return $folderInaccessible;
339-
}
340-
341-
/**
342-
* Determines is the OS is Windows or not
343-
*
344-
* @return boolean
345-
*/
346-
347-
protected function isWindows() {
348-
$isWin = (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN');
349-
return $isWin;
350-
}
351-
352-
}
1+
The traditional PHP server example has moved to a new repository: https://github.com/FineUploader/php-traditional-server.
2+
The server code is also available on packagist via composer under the name "fineuploader/php-traditional-server".

0 commit comments

Comments
 (0)