PageRenderTime 31ms CodeModel.GetById 12ms app.highlight 14ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/filesystem/file.php

https://gitlab.com/vitaliylukin91/alex-lavka
PHP | 594 lines | 340 code | 89 blank | 165 comment | 53 complexity | 655c83abfff808c84b8f98d029eb30bc MD5 | raw file
  1<?php
  2/**
  3 * @package     Joomla.Platform
  4 * @subpackage  FileSystem
  5 *
  6 * @copyright   Copyright (C) 2005 - 2015 Open Source Matters, Inc. All rights reserved.
  7 * @license     GNU General Public License version 2 or later; see LICENSE
  8 */
  9
 10defined('JPATH_PLATFORM') or die;
 11
 12/**
 13 * A File handling class
 14 *
 15 * @since  11.1
 16 */
 17class JFile
 18{
 19	/**
 20	 * Gets the extension of a file name
 21	 *
 22	 * @param   string  $file  The file name
 23	 *
 24	 * @return  string  The file extension
 25	 *
 26	 * @since   11.1
 27	 */
 28	public static function getExt($file)
 29	{
 30		$dot = strrpos($file, '.') + 1;
 31
 32		return substr($file, $dot);
 33	}
 34
 35	/**
 36	 * Strips the last extension off of a file name
 37	 *
 38	 * @param   string  $file  The file name
 39	 *
 40	 * @return  string  The file name without the extension
 41	 *
 42	 * @since   11.1
 43	 */
 44	public static function stripExt($file)
 45	{
 46		return preg_replace('#\.[^.]*$#', '', $file);
 47	}
 48
 49	/**
 50	 * Makes file name safe to use
 51	 *
 52	 * @param   string  $file  The name of the file [not full path]
 53	 *
 54	 * @return  string  The sanitised string
 55	 *
 56	 * @since   11.1
 57	 */
 58	public static function makeSafe($file)
 59	{
 60		// Remove any trailing dots, as those aren't ever valid file names.
 61		$file = rtrim($file, '.');
 62
 63		$regex = array('#(\.){2,}#', '#[^A-Za-z0-9\.\_\- ]#', '#^\.#');
 64
 65		return trim(preg_replace($regex, '', $file));
 66	}
 67
 68	/**
 69	 * Copies a file
 70	 *
 71	 * @param   string   $src          The path to the source file
 72	 * @param   string   $dest         The path to the destination file
 73	 * @param   string   $path         An optional base path to prefix to the file names
 74	 * @param   boolean  $use_streams  True to use streams
 75	 *
 76	 * @return  boolean  True on success
 77	 *
 78	 * @since   11.1
 79	 */
 80	public static function copy($src, $dest, $path = null, $use_streams = false)
 81	{
 82		$pathObject = new JFilesystemWrapperPath;
 83
 84		// Prepend a base path if it exists
 85		if ($path)
 86		{
 87			$src = $pathObject->clean($path . '/' . $src);
 88			$dest = $pathObject->clean($path . '/' . $dest);
 89		}
 90
 91		// Check src path
 92		if (!is_readable($src))
 93		{
 94			JLog::add(JText::sprintf('JLIB_FILESYSTEM_ERROR_JFILE_FIND_COPY', $src), JLog::WARNING, 'jerror');
 95
 96			return false;
 97		}
 98
 99		if ($use_streams)
100		{
101			$stream = JFactory::getStream();
102
103			if (!$stream->copy($src, $dest))
104			{
105				JLog::add(JText::sprintf('JLIB_FILESYSTEM_ERROR_JFILE_STREAMS', $src, $dest, $stream->getError()), JLog::WARNING, 'jerror');
106
107				return false;
108			}
109
110			return true;
111		}
112		else
113		{
114			$FTPOptions = JClientHelper::getCredentials('ftp');
115
116			if ($FTPOptions['enabled'] == 1)
117			{
118				// Connect the FTP client
119				$ftp = JClientFtp::getInstance($FTPOptions['host'], $FTPOptions['port'], array(), $FTPOptions['user'], $FTPOptions['pass']);
120
121				// If the parent folder doesn't exist we must create it
122				if (!file_exists(dirname($dest)))
123				{
124					$folderObject = new JFilesystemWrapperFolder;
125					$folderObject->create(dirname($dest));
126				}
127
128				// Translate the destination path for the FTP account
129				$dest = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $dest), '/');
130
131				if (!$ftp->store($src, $dest))
132				{
133					// FTP connector throws an error
134					return false;
135				}
136
137				$ret = true;
138			}
139			else
140			{
141				if (!@ copy($src, $dest))
142				{
143					JLog::add(JText::_('JLIB_FILESYSTEM_ERROR_COPY_FAILED'), JLog::WARNING, 'jerror');
144
145					return false;
146				}
147
148				$ret = true;
149			}
150
151			return $ret;
152		}
153	}
154
155	/**
156	 * Delete a file or array of files
157	 *
158	 * @param   mixed  $file  The file name or an array of file names
159	 *
160	 * @return  boolean  True on success
161	 *
162	 * @since   11.1
163	 */
164	public static function delete($file)
165	{
166		$FTPOptions = JClientHelper::getCredentials('ftp');
167		$pathObject = new JFilesystemWrapperPath;
168
169		if (is_array($file))
170		{
171			$files = $file;
172		}
173		else
174		{
175			$files[] = $file;
176		}
177
178		// Do NOT use ftp if it is not enabled
179		if ($FTPOptions['enabled'] == 1)
180		{
181			// Connect the FTP client
182			$ftp = JClientFtp::getInstance($FTPOptions['host'], $FTPOptions['port'], array(), $FTPOptions['user'], $FTPOptions['pass']);
183		}
184
185		foreach ($files as $file)
186		{
187			$file = $pathObject->clean($file);
188
189			if (!is_file($file))
190			{
191				continue;
192			}
193
194			// Try making the file writable first. If it's read-only, it can't be deleted
195			// on Windows, even if the parent folder is writable
196			@chmod($file, 0777);
197
198			// In case of restricted permissions we zap it one way or the other
199			// as long as the owner is either the webserver or the ftp
200			if (@unlink($file))
201			{
202				// Do nothing
203			}
204			elseif ($FTPOptions['enabled'] == 1)
205			{
206				$file = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $file), '/');
207
208				if (!$ftp->delete($file))
209				{
210					// FTP connector throws an error
211
212					return false;
213				}
214			}
215			else
216			{
217				$filename = basename($file);
218				JLog::add(JText::sprintf('JLIB_FILESYSTEM_DELETE_FAILED', $filename), JLog::WARNING, 'jerror');
219
220				return false;
221			}
222		}
223
224		return true;
225	}
226
227	/**
228	 * Moves a file
229	 *
230	 * @param   string   $src          The path to the source file
231	 * @param   string   $dest         The path to the destination file
232	 * @param   string   $path         An optional base path to prefix to the file names
233	 * @param   boolean  $use_streams  True to use streams
234	 *
235	 * @return  boolean  True on success
236	 *
237	 * @since   11.1
238	 */
239	public static function move($src, $dest, $path = '', $use_streams = false)
240	{
241		$pathObject = new JFilesystemWrapperPath;
242
243		if ($path)
244		{
245			$src = $pathObject->clean($path . '/' . $src);
246			$dest = $pathObject->clean($path . '/' . $dest);
247		}
248
249		// Check src path
250		if (!is_readable($src))
251		{
252			JLog::add(JText::_('JLIB_FILESYSTEM_CANNOT_FIND_SOURCE_FILE'), JLog::WARNING, 'jerror');
253
254			return false;
255		}
256
257		if ($use_streams)
258		{
259			$stream = JFactory::getStream();
260
261			if (!$stream->move($src, $dest))
262			{
263				JLog::add(JText::sprintf('JLIB_FILESYSTEM_ERROR_JFILE_MOVE_STREAMS', $stream->getError()), JLog::WARNING, 'jerror');
264
265				return false;
266			}
267
268			return true;
269		}
270		else
271		{
272			$FTPOptions = JClientHelper::getCredentials('ftp');
273
274			if ($FTPOptions['enabled'] == 1)
275			{
276				// Connect the FTP client
277				$ftp = JClientFtp::getInstance($FTPOptions['host'], $FTPOptions['port'], array(), $FTPOptions['user'], $FTPOptions['pass']);
278
279				// Translate path for the FTP account
280				$src = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $src), '/');
281				$dest = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $dest), '/');
282
283				// Use FTP rename to simulate move
284				if (!$ftp->rename($src, $dest))
285				{
286					JLog::add(JText::_('JLIB_FILESYSTEM_ERROR_RENAME_FILE'), JLog::WARNING, 'jerror');
287
288					return false;
289				}
290			}
291			else
292			{
293				if (!@ rename($src, $dest))
294				{
295					JLog::add(JText::_('JLIB_FILESYSTEM_ERROR_RENAME_FILE'), JLog::WARNING, 'jerror');
296
297					return false;
298				}
299			}
300
301			return true;
302		}
303	}
304
305	/**
306	 * Read the contents of a file
307	 *
308	 * @param   string   $filename   The full file path
309	 * @param   boolean  $incpath    Use include path
310	 * @param   integer  $amount     Amount of file to read
311	 * @param   integer  $chunksize  Size of chunks to read
312	 * @param   integer  $offset     Offset of the file
313	 *
314	 * @return  mixed  Returns file contents or boolean False if failed
315	 *
316	 * @since   11.1
317	 * @deprecated  13.3 (Platform) & 4.0 (CMS) - Use the native file_get_contents() instead.
318	 */
319	public static function read($filename, $incpath = false, $amount = 0, $chunksize = 8192, $offset = 0)
320	{
321		JLog::add(__METHOD__ . ' is deprecated. Use native file_get_contents() syntax.', JLog::WARNING, 'deprecated');
322
323		$data = null;
324
325		if ($amount && $chunksize > $amount)
326		{
327			$chunksize = $amount;
328		}
329
330		if (false === $fh = fopen($filename, 'rb', $incpath))
331		{
332			JLog::add(JText::sprintf('JLIB_FILESYSTEM_ERROR_READ_UNABLE_TO_OPEN_FILE', $filename), JLog::WARNING, 'jerror');
333
334			return false;
335		}
336
337		clearstatcache();
338
339		if ($offset)
340		{
341			fseek($fh, $offset);
342		}
343
344		if ($fsize = @ filesize($filename))
345		{
346			if ($amount && $fsize > $amount)
347			{
348				$data = fread($fh, $amount);
349			}
350			else
351			{
352				$data = fread($fh, $fsize);
353			}
354		}
355		else
356		{
357			$data = '';
358
359			/*
360			 * While it's:
361			 * 1: Not the end of the file AND
362			 * 2a: No Max Amount set OR
363			 * 2b: The length of the data is less than the max amount we want
364			 */
365			while (!feof($fh) && (!$amount || strlen($data) < $amount))
366			{
367				$data .= fread($fh, $chunksize);
368			}
369		}
370
371		fclose($fh);
372
373		return $data;
374	}
375
376	/**
377	 * Write contents to a file
378	 *
379	 * @param   string   $file         The full file path
380	 * @param   string   &$buffer      The buffer to write
381	 * @param   boolean  $use_streams  Use streams
382	 *
383	 * @return  boolean  True on success
384	 *
385	 * @since   11.1
386	 */
387	public static function write($file, &$buffer, $use_streams = false)
388	{
389		@set_time_limit(ini_get('max_execution_time'));
390
391		// If the destination directory doesn't exist we need to create it
392		if (!file_exists(dirname($file)))
393		{
394			$folderObject = new JFilesystemWrapperFolder;
395
396			if ($folderObject->create(dirname($file)) == false)
397			{
398				return false;
399			}
400		}
401
402		if ($use_streams)
403		{
404			$stream = JFactory::getStream();
405
406			// Beef up the chunk size to a meg
407			$stream->set('chunksize', (1024 * 1024));
408
409			if (!$stream->writeFile($file, $buffer))
410			{
411				JLog::add(JText::sprintf('JLIB_FILESYSTEM_ERROR_WRITE_STREAMS', $file, $stream->getError()), JLog::WARNING, 'jerror');
412
413				return false;
414			}
415
416			return true;
417		}
418		else
419		{
420			$FTPOptions = JClientHelper::getCredentials('ftp');
421			$pathObject = new JFilesystemWrapperPath;
422
423			if ($FTPOptions['enabled'] == 1)
424			{
425				// Connect the FTP client
426				$ftp = JClientFtp::getInstance($FTPOptions['host'], $FTPOptions['port'], array(), $FTPOptions['user'], $FTPOptions['pass']);
427
428				// Translate path for the FTP account and use FTP write buffer to file
429				$file = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $file), '/');
430				$ret = $ftp->write($file, $buffer);
431			}
432			else
433			{
434				$file = $pathObject->clean($file);
435				$ret = is_int(file_put_contents($file, $buffer)) ? true : false;
436			}
437
438			return $ret;
439		}
440	}
441
442	/**
443	 * Moves an uploaded file to a destination folder
444	 *
445	 * @param   string   $src              The name of the php (temporary) uploaded file
446	 * @param   string   $dest             The path (including filename) to move the uploaded file to
447	 * @param   boolean  $use_streams      True to use streams
448	 * @param   boolean  $allow_unsafe     Allow the upload of unsafe files
449	 * @param   boolean  $safeFileOptions  Options to JFilterInput::isSafeFile
450	 *
451	 * @return  boolean  True on success
452	 *
453	 * @since   11.1
454	 */
455	public static function upload($src, $dest, $use_streams = false, $allow_unsafe = false, $safeFileOptions = array())
456	{
457		if (!$allow_unsafe)
458		{
459			$descriptor = array(
460				'tmp_name' => $src,
461				'name'     => basename($dest),
462				'type'     => '',
463				'error'    => '',
464				'size'     => '',
465			);
466
467			$isSafe = JFilterInput::isSafeFile($descriptor, $safeFileOptions);
468
469			if (!$isSafe)
470			{
471				JLog::add(JText::sprintf('JLIB_FILESYSTEM_ERROR_WARNFS_ERR03', $dest), JLog::WARNING, 'jerror');
472
473				return false;
474			}
475		}
476
477		// Ensure that the path is valid and clean
478		$pathObject = new JFilesystemWrapperPath;
479		$dest = $pathObject->clean($dest);
480
481		// Create the destination directory if it does not exist
482		$baseDir = dirname($dest);
483
484		if (!file_exists($baseDir))
485		{
486			$folderObject = new JFilesystemWrapperFolder;
487			$folderObject->create($baseDir);
488		}
489
490		if ($use_streams)
491		{
492			$stream = JFactory::getStream();
493
494			if (!$stream->upload($src, $dest))
495			{
496				JLog::add(JText::sprintf('JLIB_FILESYSTEM_ERROR_UPLOAD', $stream->getError()), JLog::WARNING, 'jerror');
497
498				return false;
499			}
500
501			return true;
502		}
503		else
504		{
505			$FTPOptions = JClientHelper::getCredentials('ftp');
506			$ret = false;
507
508			if ($FTPOptions['enabled'] == 1)
509			{
510				// Connect the FTP client
511				$ftp = JClientFtp::getInstance($FTPOptions['host'], $FTPOptions['port'], array(), $FTPOptions['user'], $FTPOptions['pass']);
512
513				// Translate path for the FTP account
514				$dest = $pathObject->clean(str_replace(JPATH_ROOT, $FTPOptions['root'], $dest), '/');
515
516				// Copy the file to the destination directory
517				if (is_uploaded_file($src) && $ftp->store($src, $dest))
518				{
519					unlink($src);
520					$ret = true;
521				}
522				else
523				{
524					JLog::add(JText::_('JLIB_FILESYSTEM_ERROR_WARNFS_ERR02'), JLog::WARNING, 'jerror');
525				}
526			}
527			else
528			{
529				if (is_writeable($baseDir) && move_uploaded_file($src, $dest))
530				{
531					// Short circuit to prevent file permission errors
532					if ($pathObject->setPermissions($dest))
533					{
534						$ret = true;
535					}
536					else
537					{
538						JLog::add(JText::_('JLIB_FILESYSTEM_ERROR_WARNFS_ERR01'), JLog::WARNING, 'jerror');
539					}
540				}
541				else
542				{
543					JLog::add(JText::_('JLIB_FILESYSTEM_ERROR_WARNFS_ERR02'), JLog::WARNING, 'jerror');
544				}
545			}
546
547			return $ret;
548		}
549	}
550
551	/**
552	 * Wrapper for the standard file_exists function
553	 *
554	 * @param   string  $file  File path
555	 *
556	 * @return  boolean  True if path is a file
557	 *
558	 * @since   11.1
559	 */
560	public static function exists($file)
561	{
562		$pathObject = new JFilesystemWrapperPath;
563
564		return is_file($pathObject->clean($file));
565	}
566
567	/**
568	 * Returns the name, without any path.
569	 *
570	 * @param   string  $file  File path
571	 *
572	 * @return  string  filename
573	 *
574	 * @since   11.1
575	 * @deprecated  13.3 (Platform) & 4.0 (CMS) - Use basename() instead.
576	 */
577	public static function getName($file)
578	{
579		JLog::add(__METHOD__ . ' is deprecated. Use native basename() syntax.', JLog::WARNING, 'deprecated');
580
581		// Convert back slashes to forward slashes
582		$file = str_replace('\\', '/', $file);
583		$slash = strrpos($file, '/');
584
585		if ($slash !== false)
586		{
587			return substr($file, $slash + 1);
588		}
589		else
590		{
591			return $file;
592		}
593	}
594}