Test Failed
Push — master ( cd42b5...841446 )
by
unknown
16:44 queued 06:09
created

UploadHandler::doUpload()   C

Complexity

Conditions 15
Paths 49

Size

Total Lines 131
Code Lines 78

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 15
eloc 78
c 1
b 0
f 0
nc 49
nop 0
dl 0
loc 131
rs 5.2133

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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\Util\Logger;
18
19
class UploadHandler {
20
	public const LOG_CONTEXT = "UploadHandler"; // Context for the Logger
21
22
	public static function doUpload() {
23
		// parse account id.
24
		if (isset($_POST["parentID"])) { // will be set if a standard upload is used.
25
			$dstID = $_POST["parentID"];
26
		}
27
		else {
28
			if (isset($_SERVER['HTTP_X_FILE_DESTINATION'])) { // will be set if the upload is a ajax upload.
29
				$dstID = $_SERVER['HTTP_X_FILE_DESTINATION'];
30
			}
31
			else {
32
				Logger::error(self::LOG_CONTEXT, "upload failed: No destination given");
33
				echo json_encode(['success' => false, 'response' => 'No destination given', 'message' => 'No destination given']);
34
35
				exit();
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...
36
			}
37
		}
38
39
		$accountID = substr($dstID, 3, (strpos($dstID, '/') - 3));
40
41
		// relative node ID. We need to trim off the #R# and account ID
42
		$relNodeId = substr($dstID, strpos($dstID, '/'));
43
44
		// Initialize the account and backendstore
45
		$accountStore = new \Files\Core\AccountStore();
46
		$backendStore = \Files\Backend\BackendStore::getInstance();
47
48
		$account = $accountStore->getAccount($accountID);
49
50
		// initialize the backend
51
		$initializedBackend = $backendStore->getInstanceOfBackend($account->getBackend());
52
		$initializedBackend->init_backend($account->getBackendConfig());
53
54
		try {
55
			$initializedBackend->open();
56
		}
57
		catch (\Files\Backend\Exception $e) {
58
			Logger::error(self::LOG_CONTEXT, "backend initialization failed: " . $e->getMessage());
59
			echo json_encode(['success' => false, 'response' => $e->getCode(), 'message' => $e->getMessage()]);
60
61
			exit();
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'], $_SERVER['HTTP_X_FILE_SIZE'])) { // use the ajax method
66
			$targetPath = stringToUTF8Encode($relNodeId . $_SERVER['HTTP_X_FILE_NAME']);
67
			// check if backend supports streaming - this is the preferred way to upload files!
68
			if ($initializedBackend->supports(\Files\Backend\BackendStore::FEATURE_STREAMING)) {
69
				$fileReader = fopen('php://input', "r");
70
				$targetPath = UploadHandler::checkFilesNameConflict($targetPath, $initializedBackend, $relNodeId);
71
				$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

71
				/** @scrutinizer ignore-call */ 
72
    $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...
72
73
				while (true) {
74
					set_time_limit(0);
75
					$buffer = fgets($fileReader, 4096);
76
					if (strlen($buffer) == 0) {
77
						fclose($fileReader);
78
						fclose($fileWriter);
79
						break;
80
					}
81
82
					fwrite($fileWriter, $buffer);
83
				}
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(['success' => true, 'parent' => $dstID, 'item' => $targetPath]);
111
112
			exit();
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...
113
		}   // upload the standard way with $_FILES
114
		$items = [];
115
116
		try {
117
			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...
118
				$targetPath = stringToUTF8Encode($relNodeId . $_FILES['attachments']['name'][$i]);
119
120
				// upload the file
121
				// check if backend supports streaming - this is the preferred way to upload files!
122
				if ($initializedBackend->supports(\Files\Backend\BackendStore::FEATURE_STREAMING)) {
123
					$fileReader = fopen($_FILES['attachments']['tmp_name'][$i], "r");
124
					$fileWriter = $initializedBackend->getStreamwriter($targetPath);
125
126
					while (true) {
127
						set_time_limit(0);
128
						$buffer = fgets($fileReader, 4096);
129
						if (strlen($buffer) == 0) {
130
							fclose($fileReader);
131
							fclose($fileWriter);
132
							break;
133
						}
134
135
						fwrite($fileWriter, $buffer);
136
					}
137
				}
138
				else { // use the normal way - might have a high memory footprint
139
					$initializedBackend->put_file($targetPath, $_FILES['attachments']['tmp_name'][$i]);
140
				}
141
142
				$items[] = ['tmp_name' => $_FILES['attachments']['tmp_name'][$i], 'name' => $_FILES['attachments']['name'][$i]];
143
			}
144
			echo json_encode(['success' => true, 'parent' => $dstID, 'items' => $items]);
145
146
			exit();
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
		catch (\Files\Backend\Exception $e) {
149
			Logger::error(self::LOG_CONTEXT, "upload failed: " . $e->getMessage());
150
			echo json_encode(['success' => false, 'response' => $e->getCode(), 'message' => $e->getMessage()]);
151
152
			exit();
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...
153
		}
154
	}
155
156
	/**
157
	 * Create a unique file name if file is already exist in backend and user
158
	 * wants to keep both on server.
159
	 *
160
	 * @param string $targetPath         targeted files path
161
	 * @param object $initializedBackend Supported abstract backend object (i.e fpt,smb,owncloud etc.. )
162
	 * @param string $relNodeId          relay node id
163
	 *
164
	 * @return string target file path
165
	 */
166
	public static function checkFilesNameConflict($targetPath, $initializedBackend, $relNodeId) {
167
		$keepBoth = isset($_REQUEST["keep_both"]) ? $_REQUEST["keep_both"] : false;
168
		// Check if file was already exist in directory and $keepBoth is true
169
		// then append the counter in files name.
170
		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

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