core-bundle/src/Resources/contao/library/Contao/Dbafs.php
public static function addResource($strResource, $blnUpdateFolders=true)
	{
		$strUploadPath = Config::get('uploadPath') . '/';
		$rootDir = System::getContainer()->getParameter('kernel.project_dir');

		// Remove trailing slashes (see #5707)
		if (substr($strResource, -1) == '/')
		{
			$strResource = substr($strResource, 0, -1);
		}

		// Normalize the path (see #6034)
		$strResource = str_replace(array('\\', '//'), '/', $strResource);

		// The resource does not exist or lies outside the upload directory
		if ($strResource == '' || strncmp($strResource, $strUploadPath, \strlen($strUploadPath)) !== 0 || !file_exists($rootDir . '/' . $strResource))
		{
			throw new \InvalidArgumentException("Invalid resource $strResource");
		}

		$objModel = FilesModel::findByPath($strResource);

		// Return the model if it exists already
		if ($objModel !== null)
		{
			$objFile = ($objModel->type == 'folder') ? new Folder($objModel->path) : new File($objModel->path);

			// Update the timestamp and file hash (see #4818, #7828)
			if ($objModel->hash != $objFile->hash)
			{
				$objModel->tstamp = time();
				$objModel->hash   = $objFile->hash;
				$objModel->save();
			}

			return $objModel;
		}

		$arrPaths    = array();
		$arrChunks   = explode('/', $strResource);
		$strPath     = array_shift($arrChunks);
		$arrPids     = array($strPath => null);
		$arrUpdate   = array($strResource);
		$objDatabase = Database::getInstance();

		// Build the paths
		while (\count($arrChunks))
		{
			$strPath .= '/' . array_shift($arrChunks);
			$arrPaths[] = $strPath;
		}

		unset($arrChunks);

		$objModels = FilesModel::findMultipleByPaths($arrPaths);

		// Unset the entries in $arrPaths if the DB entry exists
		if ($objModels !== null)
		{
			while ($objModels->next())
			{
				if (($i = array_search($objModels->path, $arrPaths)) !== false)
				{
					unset($arrPaths[$i]);
					$arrPids[$objModels->path] = $objModels->uuid;
				}
			}
		}

		$arrPaths = array_values($arrPaths);

		// If the resource is a folder, also add its contents
		if (is_dir($rootDir . '/' . $strResource))
		{
			/** @var \SplFileInfo[] $objFiles */
			$objFiles = new \RecursiveIteratorIterator(
				new SyncExclude(
					new \RecursiveDirectoryIterator(
						$rootDir . '/' . $strResource,
						\FilesystemIterator::UNIX_PATHS|\FilesystemIterator::FOLLOW_SYMLINKS|\FilesystemIterator::SKIP_DOTS
					)
				), \RecursiveIteratorIterator::SELF_FIRST
			);

			// Add the relative path
			foreach ($objFiles as $objFile)
			{
				$strRelpath = StringUtil::stripRootDir($objFile->getPathname());

				if ($objFile->isDir())
				{
					$arrUpdate[] = $strRelpath;
				}

				$arrPaths[] = $strRelpath;
			}
		}

		$objReturn = null;

		// Create the new resources
		foreach ($arrPaths as $strPath)
		{
			if (\in_array(basename($strPath), array('.public', '.nosync')))
			{
				continue;
			}

			$strParent = \dirname($strPath);

			// The parent ID should be in $arrPids
			// Do not use isset() here, because the PID can be null
			if (\array_key_exists($strParent, $arrPids))
			{
				$strPid = $arrPids[$strParent];
			}
			else
			{
				throw new \Exception("No parent entry for $strParent");
			}

			// Create the file or folder
			if (is_file($rootDir . '/' . $strPath))
			{
				$objFile = new File($strPath);

				$objModel = new FilesModel();
				$objModel->pid       = $strPid;
				$objModel->tstamp    = time();
				$objModel->name      = $objFile->name;
				$objModel->type      = 'file';
				$objModel->path      = $objFile->path;
				$objModel->extension = $objFile->extension;
				$objModel->hash      = $objFile->hash;
				$objModel->uuid      = $objDatabase->getUuid();
				$objModel->save();

				$arrPids[$objFile->path] = $objModel->uuid;
			}
			else
			{
				$objFolder = new Folder($strPath);

				$objModel = new FilesModel();
				$objModel->pid       = $strPid;
				$objModel->tstamp    = time();
				$objModel->name      = $objFolder->name;
				$objModel->type      = 'folder';
				$objModel->path      = $objFolder->path;
				$objModel->extension = '';
				$objModel->uuid      = $objDatabase->getUuid();
				$objModel->save();

				$arrPids[$objFolder->path] = $objModel->uuid;
			}

			// Store the model to be returned (see #5979)
			if ($objModel->path == $strResource)
			{
				$objReturn = $objModel;
			}
		}

		// Update the folder hashes from bottom up after all file hashes are set
		foreach (array_reverse($arrPaths) as $strPath)
		{
			if (is_dir($rootDir . '/' . $strPath))
			{
				$objModel = FilesModel::findByPath($strPath);
				$objModel->hash = static::getFolderHash($strPath);
				$objModel->save();
			}
		}

		// Update the folder hashes
		if ($blnUpdateFolders)
		{
			static::updateFolderHashes($arrUpdate);
		}

		return $objReturn;
	}
public static function addResource($strResource, $blnUpdateFolders=true)
	{
		$strUploadPath = Config::get('uploadPath') . '/';
		$rootDir = System::getContainer()->getParameter('kernel.project_dir');

		// Remove trailing slashes (see #5707)
		if (substr($strResource, -1) == '/')
		{
			$strResource = substr($strResource, 0, -1);
		}

		// Normalize the path (see #6034)
		$strResource = str_replace(array('\\', '//'), '/', $strResource);

		// The resource does not exist or lies outside the upload directory
		if ($strResource == '' || strncmp($strResource, $strUploadPath, \strlen($strUploadPath)) !== 0 || !file_exists($rootDir . '/' . $strResource))
		{
			throw new \InvalidArgumentException("Invalid resource $strResource");
		}

		$objModel = FilesModel::findByPath($strResource);

		// Return the model if it exists already
		if ($objModel !== null)
		{
			$objFile = ($objModel->type == 'folder') ? new Folder($objModel->path) : new File($objModel->path);

			// Update the timestamp and file hash (see #4818, #7828)
			if ($objModel->hash != $objFile->hash)
			{
				$objModel->tstamp = time();
				$objModel->hash   = $objFile->hash;
				$objModel->save();
			}

			return $objModel;
		}

		$arrPaths    = array();
		$arrChunks   = explode('/', $strResource);
		$strPath     = array_shift($arrChunks);
		$arrPids     = array($strPath => null);
		$arrUpdate   = array($strResource);
		$objDatabase = Database::getInstance();

		// Build the paths
		while (\count($arrChunks))
		{
			$strPath .= '/' . array_shift($arrChunks);
			$arrPaths[] = $strPath;
		}

		unset($arrChunks);

		$objModels = FilesModel::findMultipleByPaths($arrPaths);

		// Unset the entries in $arrPaths if the DB entry exists
		if ($objModels !== null)
		{
			while ($objModels->next())
			{
				if (($i = array_search($objModels->path, $arrPaths)) !== false)
				{
					unset($arrPaths[$i]);
					$arrPids[$objModels->path] = $objModels->uuid;
				}
			}
		}

		$arrPaths = array_values($arrPaths);

		// If the resource is a folder, also add its contents
		if (is_dir($rootDir . '/' . $strResource))
		{
			/** @var \SplFileInfo[] $objFiles */
			$objFiles = new \RecursiveIteratorIterator(
				new SyncExclude(
					new \RecursiveDirectoryIterator(
						$rootDir . '/' . $strResource,
						\FilesystemIterator::UNIX_PATHS|\FilesystemIterator::FOLLOW_SYMLINKS|\FilesystemIterator::SKIP_DOTS
					)
				), \RecursiveIteratorIterator::SELF_FIRST
			);

			// Add the relative path
			foreach ($objFiles as $objFile)
			{
				$strRelpath = StringUtil::stripRootDir($objFile->getPathname());

				if ($objFile->isDir())
				{
					$arrUpdate[] = $strRelpath;
				}

				$arrPaths[] = $strRelpath;
			}
		}

		$objReturn = null;

		// Create the new resources
		foreach ($arrPaths as $strPath)
		{
			if (\in_array(basename($strPath), array('.public', '.nosync')))
			{
				continue;
			}

			$strParent = \dirname($strPath);

			// The parent ID should be in $arrPids
			// Do not use isset() here, because the PID can be null
			if (\array_key_exists($strParent, $arrPids))
			{
				$strPid = $arrPids[$strParent];
			}
			else
			{
				throw new \Exception("No parent entry for $strParent");
			}

			// Create the file or folder
			if (is_file($rootDir . '/' . $strPath))
			{
				$objFile = new File($strPath);

				$objModel = new FilesModel();
				$objModel->pid       = $strPid;
				$objModel->tstamp    = time();
				$objModel->name      = $objFile->name;
				$objModel->type      = 'file';
				$objModel->path      = $objFile->path;
				$objModel->extension = $objFile->extension;
				$objModel->hash      = $objFile->hash;
				$objModel->uuid      = $objDatabase->getUuid();
				$objModel->save();

				$arrPids[$objFile->path] = $objModel->uuid;
			}
			else
			{
				$objFolder = new Folder($strPath);

				$objModel = new FilesModel();
				$objModel->pid       = $strPid;
				$objModel->tstamp    = time();
				$objModel->name      = $objFolder->name;
				$objModel->type      = 'folder';
				$objModel->path      = $objFolder->path;
				$objModel->extension = '';
				$objModel->uuid      = $objDatabase->getUuid();
				$objModel->save();

				$arrPids[$objFolder->path] = $objModel->uuid;
			}

			// Store the model to be returned (see #5979)
			if ($objModel->path == $strResource)
			{
				$objReturn = $objModel;
			}
		}

		// Update the folder hashes from bottom up after all file hashes are set
		foreach (array_reverse($arrPaths) as $strPath)
		{
			if (is_dir($rootDir . '/' . $strPath))
			{
				$objModel = FilesModel::findByPath($strPath);
				$objModel->hash = static::getFolderHash($strPath);
				$objModel->save();
			}
		}

		// Update the folder hashes
		if ($blnUpdateFolders)
		{
			static::updateFolderHashes($arrUpdate);
		}

		return $objReturn;
	}
Adds a file or folder with its parent folders

@param string  $strResource      The path to the file or folder
@param boolean $blnUpdateFolders If true, the parent folders will be updated

@return FilesModel The files model

@throws \Exception                If a parent ID entry is missing
@throws \InvalidArgumentException If the resource is outside the upload folder