1<?php
2/*
3 * FCKeditor - The text editor for Internet - http://www.fckeditor.net
4 * Copyright (C) 2003-2010 Frederico Caldeira Knabben
5 *
6 * == BEGIN LICENSE ==
7 *
8 * Licensed under the terms of any of the following licenses at your
9 * choice:
10 *
11 *  - GNU General Public License Version 2 or later (the "GPL")
12 *    https://www.gnu.org/licenses/gpl.html
13 *
14 *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
15 *    https://www.gnu.org/licenses/lgpl.html
16 *
17 *  - Mozilla Public License Version 1.1 or later (the "MPL")
18 *    http://www.mozilla.org/MPL/MPL-1.1.html
19 *
20 * == END LICENSE ==
21 *
22 * This is the File Manager Connector for PHP.
23 */
24
25/**
26 * CombinePaths
27 *
28 * @param   string $sBasePath     sBasePath
29 * @param   string $sFolder       sFolder
30 * @return  string                Combined path
31 */
32function CombinePaths($sBasePath, $sFolder)
33{
34	return RemoveFromEnd($sBasePath, '/').'/'.RemoveFromStart($sFolder, '/');
35}
36/**
37 * GetResourceTypePath
38 *
39 * @param 	string		$resourceType	Resource type
40 * @param 	string		$sCommand		Command
41 * @return	string						Config
42 */
43function GetResourceTypePath($resourceType, $sCommand)
44{
45	global $Config;
46
47	if ($sCommand == "QuickUpload") {
48		return $Config['QuickUploadPath'][$resourceType];
49	} else {
50		return $Config['FileTypesPath'][$resourceType];
51	}
52}
53
54/**
55 * GetResourceTypeDirectory
56 *
57 * @param string $resourceType	Resource type
58 * @param string $sCommand		Command
59 * @return string
60 */
61function GetResourceTypeDirectory($resourceType, $sCommand)
62{
63	global $Config;
64	if ($sCommand == "QuickUpload") {
65		if (strlen($Config['QuickUploadAbsolutePath'][$resourceType]) > 0) {
66			return $Config['QuickUploadAbsolutePath'][$resourceType];
67		}
68
69		// Map the "UserFiles" path to a local directory.
70		return Server_MapPath($Config['QuickUploadPath'][$resourceType]);
71	} else {
72		if (strlen($Config['FileTypesAbsolutePath'][$resourceType]) > 0) {
73			return $Config['FileTypesAbsolutePath'][$resourceType];
74		}
75
76		// Map the "UserFiles" path to a local directory.
77		return Server_MapPath($Config['FileTypesPath'][$resourceType]);
78	}
79}
80
81/**
82 * GetUrlFromPath
83 *
84 * @param	string 	$resourceType	Resource type
85 * @param 	string 	$folderPath		Path
86 * @param	string	$sCommand		Command
87 * @return	string					Full url
88 */
89function GetUrlFromPath($resourceType, $folderPath, $sCommand)
90{
91	return CombinePaths(GetResourceTypePath($resourceType, $sCommand), $folderPath);
92}
93
94/**
95 * RemoveExtension
96 *
97 * @param 	string		$fileName	Filename
98 * @return	string					String without extension
99 */
100function RemoveExtension($fileName)
101{
102	return substr($fileName, 0, strrpos($fileName, '.'));
103}
104/**
105 * ServerMapFolder
106 *
107 * @param 	string	$resourceType	Resource type
108 * @param 	string	$folderPath		Folder
109 * @param 	string	$sCommand		Command
110 * @return	string
111 */
112function ServerMapFolder($resourceType, $folderPath, $sCommand)
113{
114	// Get the resource type directory.
115	$sResourceTypePath = GetResourceTypeDirectory($resourceType, $sCommand);
116
117	// Ensure that the directory exists.
118	$sErrorMsg = CreateServerFolder($sResourceTypePath);
119	if ($sErrorMsg != '') {
120		SendError(1, "Error creating folder \"{$sResourceTypePath}\" ({$sErrorMsg})");
121	}
122
123	// Return the resource type directory combined with the required path.
124	return CombinePaths($sResourceTypePath, $folderPath);
125}
126
127/**
128 * GetParentFolder
129 *
130 * @param	string	$folderPath		Folder path
131 * @return 	string					Parent folder
132 */
133function GetParentFolder($folderPath)
134{
135	$sPattern = "-[/\\\\][^/\\\\]+[/\\\\]?$-";
136	return preg_replace($sPattern, '', $folderPath);
137}
138
139/**
140 * CreateServerFolder
141 *
142 * @param 	string	$folderPath		Folder
143 * @param 	string	$lastFolder		Folder
144 * @return	string					''=success, error message otherwise
145 */
146function CreateServerFolder($folderPath, $lastFolder = null)
147{
148	global $Config;
149	$sParent = GetParentFolder($folderPath);
150
151	// Ensure the folder path has no double-slashes, or mkdir may fail on certain platforms
152	while (strpos($folderPath, '//') !== false) {
153		$folderPath = str_replace('//', '/', $folderPath);
154	}
155
156	// Check if the parent exists, or create it.
157	if (!empty($sParent) && !file_exists($sParent)) {
158		//prevents agains infinite loop when we can't create root folder
159		if (!is_null($lastFolder) && $lastFolder === $sParent) {
160			return "Can't create $folderPath directory";
161		}
162
163		$sErrorMsg = CreateServerFolder($sParent, $folderPath);
164		if ($sErrorMsg != '') {
165			return $sErrorMsg;
166		}
167	}
168
169	if (!file_exists($folderPath)) {
170		// Turn off all error reporting.
171		error_reporting(0);
172
173		$php_errormsg = '';
174		// Enable error tracking to catch the error.
175		ini_set('track_errors', '1');
176
177		if (isset($Config['ChmodOnFolderCreate']) && !$Config['ChmodOnFolderCreate']) {
178			mkdir($folderPath);
179		} else {
180			$permissions = '0777';
181			if (isset($Config['ChmodOnFolderCreate']) && $Config['ChmodOnFolderCreate']) {
182				$permissions = (string) $Config['ChmodOnFolderCreate'];
183			}
184			$permissionsdec = octdec($permissions);
185			$permissionsdec |= octdec('0111'); // Set x bit required for directories
186			dol_syslog("io.php permission = ".$permissions." ".$permissionsdec." ".decoct($permissionsdec));
187			// To create the folder with 0777 permissions, we need to set umask to zero.
188			$oldumask = umask(0);
189			mkdir($folderPath, $permissionsdec);
190			umask($oldumask);
191		}
192
193		$sErrorMsg = $php_errormsg;
194
195		// Restore the configurations.
196		ini_restore('track_errors');
197		ini_restore('error_reporting');
198
199		return $sErrorMsg;
200	} else {
201		return '';
202	}
203}
204
205/**
206 * Get Root Path
207 *
208 * @return  string              real path
209 */
210function GetRootPath()
211{
212	if (!isset($_SERVER)) {
213		global $_SERVER;
214	}
215	$sRealPath = realpath('./');
216	// #2124 ensure that no slash is at the end
217	$sRealPath = rtrim($sRealPath, "\\/");
218
219	$sSelfPath = $_SERVER['PHP_SELF'];
220	$sSelfPath = substr($sSelfPath, 0, strrpos($sSelfPath, '/'));
221
222	$sSelfPath = str_replace('/', DIRECTORY_SEPARATOR, $sSelfPath);
223
224	$position = strpos($sRealPath, $sSelfPath);
225
226	// This can check only that this script isn't run from a virtual dir
227	// But it avoids the problems that arise if it isn't checked
228	if ($position === false || $position <> strlen($sRealPath) - strlen($sSelfPath)) {
229		SendError(1, 'Sorry, can\'t map "UserFilesPath" to a physical path. You must set the "UserFilesAbsolutePath" value in "editor/filemanager/connectors/php/config.php".');
230	}
231
232	return substr($sRealPath, 0, $position);
233}
234
235/**
236 *  Emulate the asp Server.mapPath function.
237 *  @param	string		$path		given an url path return the physical directory that it corresponds to
238 *  @return	string					Path
239 */
240function Server_MapPath($path)
241{
242	// This function is available only for Apache
243	if (function_exists('apache_lookup_uri')) {
244		$info = apache_lookup_uri($path);
245		return $info->filename.$info->path_info;
246	}
247
248	// This isn't correct but for the moment there's no other solution
249	// If this script is under a virtual directory or symlink it will detect the problem and stop
250	return GetRootPath().$path;
251}
252
253/**
254 * Is Allowed Extension
255 *
256 * @param   string $sExtension      File extension
257 * @param   string $resourceType    ressource type
258 * @return  boolean                 true or false
259 */
260function IsAllowedExt($sExtension, $resourceType)
261{
262	global $Config;
263	// Get the allowed and denied extensions arrays.
264	$arAllowed = $Config['AllowedExtensions'][$resourceType];
265	$arDenied = $Config['DeniedExtensions'][$resourceType];
266
267	if (count($arAllowed) > 0 && !in_array($sExtension, $arAllowed)) {
268		return false;
269	}
270
271	if (count($arDenied) > 0 && in_array($sExtension, $arDenied)) {
272		return false;
273	}
274
275	return true;
276}
277
278/**
279 * Is Allowed Type
280 *
281 * @param   string $resourceType    ressource type
282 * @return  boolean                 true or false
283 */
284function IsAllowedType($resourceType)
285{
286	global $Config;
287	if (!in_array($resourceType, $Config['ConfigAllowedTypes'])) {
288		return false;
289	}
290
291	return true;
292}
293
294/**
295 * IsAllowedCommand
296 *
297 * @param   string		$sCommand		Command
298 * @return  boolean						True or false
299 */
300function IsAllowedCommand($sCommand)
301{
302	global $Config;
303
304	if (!in_array($sCommand, $Config['ConfigAllowedCommands'])) {
305		return false;
306	}
307
308	return true;
309}
310
311/**
312 * GetCurrentFolder
313 *
314 * @return	string		current folder
315 */
316function GetCurrentFolder()
317{
318	if (!isset($_GET)) {
319		global $_GET;
320	}
321	$sCurrentFolder = isset($_GET['CurrentFolder']) ? GETPOST('CurrentFolder', '', 1) : '/';
322
323	// Check the current folder syntax (must begin and start with a slash).
324	if (!preg_match('|/$|', $sCurrentFolder)) {
325		$sCurrentFolder .= '/';
326	}
327	if (strpos($sCurrentFolder, '/') !== 0) {
328		$sCurrentFolder = '/'.$sCurrentFolder;
329	}
330
331	// Ensure the folder path has no double-slashes
332	while (strpos($sCurrentFolder, '//') !== false) {
333		$sCurrentFolder = str_replace('//', '/', $sCurrentFolder);
334	}
335
336	// Check for invalid folder paths (..)
337	if (strpos($sCurrentFolder, '..') || strpos($sCurrentFolder, "\\")) {
338		SendError(102, '');
339	}
340
341	if (preg_match(",(/\.)|[[:cntrl:]]|(//)|(\\\\)|([\:\*\?\"\<\>\|]),", $sCurrentFolder)) {
342		SendError(102, '');
343	}
344
345	return $sCurrentFolder;
346}
347
348/**
349 * Do a cleanup of the folder name to avoid possible problems
350 *
351 * @param	string	$sNewFolderName		Folder
352 * @return	string						Folder sanitized
353 */
354function SanitizeFolderName($sNewFolderName)
355{
356	$sNewFolderName = stripslashes($sNewFolderName);
357
358	// Remove . \ / | : ? * " < >
359	$sNewFolderName = preg_replace('/\\.|\\\\|\\/|\\||\\:|\\?|\\*|"|<|>|[[:cntrl:]]/', '_', $sNewFolderName);
360
361	return $sNewFolderName;
362}
363
364/**
365 * Do a cleanup of the file name to avoid possible problems
366 *
367 * @param	string	$sNewFileName		Folder
368 * @return	string						Folder sanitized
369 */
370function SanitizeFileName($sNewFileName)
371{
372	global $Config;
373
374	$sNewFileName = stripslashes($sNewFileName);
375
376	// Replace dots in the name with underscores (only one dot can be there... security issue).
377	if ($Config['ForceSingleExtension']) {
378		$sNewFileName = preg_replace('/\\.(?![^.]*$)/', '_', $sNewFileName);
379	}
380
381	// Remove \ / | : ? * " < >
382	$sNewFileName = preg_replace('/\\\\|\\/|\\||\\:|\\?|\\*|"|<|>|[[:cntrl:]]/', '_', $sNewFileName);
383
384	return $sNewFileName;
385}
386
387/**
388 * This is the function that sends the results of the uploading process.
389 *
390 * @param	string		$errorNumber	errorNumber
391 * @param	string		$fileUrl		fileUrl
392 * @param	string		$fileName		fileName
393 * @param	string		$customMsg		customMsg
394 * @return	void
395 */
396function SendUploadResults($errorNumber, $fileUrl = '', $fileName = '', $customMsg = '')
397{
398	// Minified version of the document.domain automatic fix script (#1919).
399	// The original script can be found at _dev/domain_fix_template.js
400	echo <<<EOF
401<script type="text/javascript">
402(function(){var d=document.domain;while (true){try{var A=window.parent.document.domain;break;}catch(e) {};d=d.replace(/.*?(?:\.|$)/,'');if (d.length==0) break;try{document.domain=d;}catch (e){break;}}})();
403EOF;
404
405	if ($errorNumber && $errorNumber != 201) {
406		$fileUrl = "";
407		$fileName = "";
408	}
409
410	$rpl = array('\\' => '\\\\', '"' => '\\"');
411	echo 'window.parent.OnUploadCompleted('.$errorNumber.',"'.strtr($fileUrl, $rpl).'","'.strtr($fileName, $rpl).'", "'.strtr($customMsg, $rpl).'");';
412	echo '</script>';
413	exit;
414}
415
416
417// @CHANGE
418
419// This is the function that sends the results of the uploading process to CKE.
420/**
421 * SendCKEditorResults
422 *
423 * @param   string  $callback       callback
424 * @param   string  $sFileUrl       sFileUrl
425 * @param   string  $customMsg      customMsg
426 * @return  void
427 */
428function SendCKEditorResults($callback, $sFileUrl, $customMsg = '')
429{
430	echo '<script type="text/javascript">';
431
432	$rpl = array('\\' => '\\\\', '"' => '\\"');
433
434	echo 'window.parent.CKEDITOR.tools.callFunction("'.$callback.'","'.strtr($sFileUrl, $rpl).'", "'.strtr($customMsg, $rpl).'");';
435
436	echo '</script>';
437}
438