Test Failed
Push — master ( 647c72...cd42b5 )
by
unknown
10:25
created

UploadHandler   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 158
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 94
dl 0
loc 158
rs 10
c 0
b 0
f 0
wmc 21

2 Methods

Rating   Name   Duplication   Size   Complexity  
A checkFilesNameConflict() 0 20 5
D doUpload() 0 121 16
1
<?php
2
/**
3
 * Created by PhpStorm.
4
 * User: zdev
5
 * Date: 12.01.15
6
 * Time: 23:49
7
 */
8
9
namespace Files\Core;
10
11
require_once __DIR__ . "/class.accountstore.php";
12
13
require_once __DIR__ . "/Util/class.pathutil.php";
14
require_once __DIR__ . "/Util/util.php";
15
require_once __DIR__ . "/Util/class.logger.php";
16
17
use \Files\Core\AccountStore;
18
19
use \Files\Core\Util\PathUtil;
20
use \Files\Core\Util\Logger;
21
22
class UploadHandler
23
{
24
	const LOG_CONTEXT = "UploadHandler"; // Context for the Logger
25
26
	public static function doUpload()
27
	{
28
		// parse account id.
29
		if (isset($_POST["parentID"])) { // will be set if a standard upload is used.
30
			$dstID = $_POST["parentID"];
31
		} else {
32
			if (isset($_SERVER['HTTP_X_FILE_DESTINATION'])) { // will be set if the upload is a ajax upload.
33
				$dstID = $_SERVER['HTTP_X_FILE_DESTINATION'];
34
			} else {
35
				Logger::error(self::LOG_CONTEXT, "upload failed: No destination given");
36
				echo json_encode(array('success' => false, 'response' => 'No destination given', 'message' => 'No destination given'));
37
				die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
38
			}
39
		}
40
41
		$accountID = substr($dstID, 3, (strpos($dstID, '/') - 3));
42
43
		// relative node ID. We need to trim off the #R# and account ID
44
		$relNodeId = substr($dstID, strpos($dstID, '/'));
45
46
		// Initialize the account and backendstore
47
		$accountStore = new \Files\Core\AccountStore();
48
		$backendStore = \Files\Backend\BackendStore::getInstance();
49
50
		$account = $accountStore->getAccount($accountID);
51
52
		// initialize the backend
53
		$initializedBackend = $backendStore->getInstanceOfBackend($account->getBackend());
54
		$initializedBackend->init_backend($account->getBackendConfig());
55
56
		try {
57
			$initializedBackend->open();
58
		} catch (\Files\Backend\Exception $e) {
59
			Logger::error(self::LOG_CONTEXT, "backend initialization failed: " . $e->getMessage());
60
			echo json_encode(array('success' => false, 'response' => $e->getCode(), 'message' => $e->getMessage()));
61
			die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
62
		}
63
64
		// check if we are getting the file via the "new" method (ajax - XMLHttpRequest) or the standard way
65
		if (isset($_SERVER['HTTP_X_FILE_NAME']) && isset($_SERVER['HTTP_X_FILE_SIZE'])) { // use the ajax method
66
67
			$targetPath = stringToUTF8Encode($relNodeId . $_SERVER['HTTP_X_FILE_NAME']);
68
			// check if backend supports streaming - this is the preferred way to upload files!
69
			if ($initializedBackend->supports(\Files\Backend\BackendStore::FEATURE_STREAMING)) {
70
				$fileReader = fopen('php://input', "r");
71
				$targetPath = UploadHandler::checkFilesNameConflict($targetPath, $initializedBackend, $relNodeId);
72
				$fileWriter = $initializedBackend->getStreamwriter($targetPath);
0 ignored issues
show
Bug introduced by
The method getStreamwriter() does not exist on Files\Backend\AbstractBackend. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

72
				/** @scrutinizer ignore-call */ 
73
    $fileWriter = $initializedBackend->getStreamwriter($targetPath);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
73
74
				while (true) {
75
					set_time_limit(0);
76
					$buffer = fgets($fileReader, 4096);
77
					if (strlen($buffer) == 0) {
78
						fclose($fileReader);
79
						fclose($fileWriter);
80
						break;
81
					}
82
83
					fwrite($fileWriter, $buffer);
84
				}
85
			} else { // fallback to tmp files
86
				$targetPath = UploadHandler::checkFilesNameConflict($targetPath, $initializedBackend, $relNodeId);
87
				$targetPath = rawurldecode($targetPath);
88
				$temp_file = tempnam(TMP_PATH, "$targetPath");
0 ignored issues
show
Bug introduced by
The constant Files\Core\TMP_PATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
89
				$fileReader = fopen('php://input', "r");
90
				$fileWriter = fopen($temp_file, "w");
91
92
				// store post data to tmp file
93
				while (true) {
94
					set_time_limit(0);
95
					$buffer = fgets($fileReader, 4096);
96
					if (strlen($buffer) == 0) {
97
						fclose($fileReader);
98
						fclose($fileWriter);
99
						break;
100
					}
101
102
					fwrite($fileWriter, $buffer);
103
				}
104
105
				// upload tmp file to backend
106
				$initializedBackend->put_file($targetPath, $temp_file);
107
				// clean up tmp file
108
				unlink($temp_file);
109
			}
110
			echo json_encode(array('success' => true, 'parent' => $dstID, 'item' => $targetPath));
111
			die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
112
		} else { // upload the standard way with $_FILES
113
			$items = array();
114
			try {
115
				for ($i = 0; $i < count($_FILES['attachments']['name']); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
116
					$targetPath = stringToUTF8Encode($relNodeId . $_FILES['attachments']['name'][$i]);
117
118
					// upload the file
119
					// check if backend supports streaming - this is the preferred way to upload files!
120
					if ($initializedBackend->supports(\Files\Backend\BackendStore::FEATURE_STREAMING)) {
121
						$fileReader = fopen($_FILES['attachments']['tmp_name'][$i], "r");
122
						$fileWriter = $initializedBackend->getStreamwriter($targetPath);
123
124
						while (true) {
125
							set_time_limit(0);
126
							$buffer = fgets($fileReader, 4096);
127
							if (strlen($buffer) == 0) {
128
								fclose($fileReader);
129
								fclose($fileWriter);
130
								break;
131
							}
132
133
							fwrite($fileWriter, $buffer);
134
						}
135
					} else { // use the normal way - might have a high memory footprint
136
						$initializedBackend->put_file($targetPath, $_FILES['attachments']['tmp_name'][$i]);
137
					}
138
139
					$items[] = array('tmp_name' => $_FILES['attachments']['tmp_name'][$i], 'name' => $_FILES['attachments']['name'][$i]);
140
				}
141
				echo json_encode(array('success' => true, 'parent' => $dstID, 'items' => $items));
142
				die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
143
			} catch (\Files\Backend\Exception $e) {
144
				Logger::error(self::LOG_CONTEXT, "upload failed: " . $e->getMessage());
145
				echo json_encode(array('success' => false, 'response' => $e->getCode(), 'message' => $e->getMessage()));
146
				die();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
147
			}
148
		}
149
	}
150
151
	/**
152
	 * Create a unique file name if file is already exist in backend and user
153
	 * wants to keep both on server.
154
	 *
155
	 * @param string $targetPath targeted files path
156
	 * @param Object $initializedBackend Supported abstract backend object (i.e fpt,smb,owncloud etc.. )
157
	 * @param string $relNodeId relay node id
158
	 * @return string target file path
159
	 */
160
	public static function checkFilesNameConflict($targetPath, $initializedBackend, $relNodeId)
161
	{
162
		$keepBoth = isset($_REQUEST["keep_both"])? $_REQUEST["keep_both"] : false;
163
		// Check if file was already exist in directory and $keepBoth is true
164
		// then append the counter in files name.
165
		if (strtolower($keepBoth) === 'true') {
0 ignored issues
show
Bug introduced by
It seems like $keepBoth can also be of type false; however, parameter $string of strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

165
		if (strtolower(/** @scrutinizer ignore-type */ $keepBoth) === 'true') {
Loading history...
166
			$lsNodes = $initializedBackend->ls($relNodeId);
167
			$nodeExist = array_key_exists(rawurldecode($targetPath), $lsNodes);
168
			if($nodeExist) {
169
				$i = 1;
170
				$targetPathInfo = pathinfo($targetPath);
171
				do {
172
					$targetPath = $targetPathInfo["dirname"] . "/" . $targetPathInfo["filename"] . " (" . $i . ")." . $targetPathInfo["extension"];
173
					$targetPath = str_replace('//', '/', $targetPath);
174
					$i++;
175
				} while (array_key_exists(rawurldecode($targetPath), $lsNodes));
176
			}
177
		}
178
179
		return $targetPath;
180
	}
181
}