Contao\Dbafs::syncFiles PHP Method

syncFiles() public static method

Synchronize the file system with the database
public static syncFiles ( ) : string
return string The path to the synchronization log file
    public static function syncFiles()
    {
        @ini_set('max_execution_time', 0);
        // Consider the suhosin.memory_limit (see #7035)
        if (extension_loaded('suhosin')) {
            if (($limit = ini_get('suhosin.memory_limit')) !== '') {
                @ini_set('memory_limit', $limit);
            }
        } else {
            @ini_set('memory_limit', -1);
        }
        $objDatabase = \Database::getInstance();
        // Lock the files table
        $objDatabase->lockTables(array('tl_files' => 'WRITE'));
        // Reset the "found" flag
        $objDatabase->query("UPDATE tl_files SET found=''");
        /** @var \SplFileInfo[] $objFiles */
        $objFiles = new \RecursiveIteratorIterator(new \Filter\SyncExclude(new \RecursiveDirectoryIterator(TL_ROOT . '/' . \Config::get('uploadPath'), \FilesystemIterator::UNIX_PATHS | \FilesystemIterator::FOLLOW_SYMLINKS | \FilesystemIterator::SKIP_DOTS)), \RecursiveIteratorIterator::SELF_FIRST);
        $strLog = 'system/tmp/' . md5(uniqid(mt_rand(), true));
        // Open the log file
        $objLog = new \File($strLog);
        $objLog->truncate();
        $arrModels = array();
        // Create or update the database entries
        foreach ($objFiles as $objFile) {
            $strRelpath = str_replace(TL_ROOT . '/', '', $objFile->getPathname());
            // Get all subfiles in a single query
            if ($objFile->isDir()) {
                $objSubfiles = \FilesModel::findMultipleFilesByFolder($strRelpath);
                if ($objSubfiles !== null) {
                    while ($objSubfiles->next()) {
                        $arrModels[$objSubfiles->path] = $objSubfiles->current();
                    }
                }
            }
            // Get the model
            if (isset($arrModels[$strRelpath])) {
                $objModel = $arrModels[$strRelpath];
            } else {
                $objModel = \FilesModel::findByPath($strRelpath);
            }
            if ($objModel === null) {
                // Add a log entry
                $objLog->append("[Added] {$strRelpath}");
                // Get the parent folder
                $strParent = dirname($strRelpath);
                // Get the parent ID
                if ($strParent == \Config::get('uploadPath')) {
                    $strPid = null;
                } else {
                    $objParent = \FilesModel::findByPath($strParent);
                    if ($objParent === null) {
                        throw new \Exception("No parent entry for {$strParent}");
                    }
                    $strPid = $objParent->uuid;
                }
                // Create the file or folder
                if (is_file(TL_ROOT . '/' . $strRelpath)) {
                    $objFile = new \File($strRelpath);
                    $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->found = 2;
                    $objModel->hash = $objFile->hash;
                    $objModel->uuid = $objDatabase->getUuid();
                    $objModel->save();
                } else {
                    $objFolder = new \Folder($strRelpath);
                    $objModel = new \FilesModel();
                    $objModel->pid = $strPid;
                    $objModel->tstamp = time();
                    $objModel->name = $objFolder->name;
                    $objModel->type = 'folder';
                    $objModel->path = $objFolder->path;
                    $objModel->extension = '';
                    $objModel->found = 2;
                    $objModel->hash = $objFolder->hash;
                    $objModel->uuid = $objDatabase->getUuid();
                    $objModel->save();
                }
            } else {
                // Check whether the MD5 hash has changed
                $objResource = $objFile->isDir() ? new \Folder($strRelpath) : new \File($strRelpath);
                $strType = $objModel->hash != $objResource->hash ? 'Changed' : 'Unchanged';
                // Add a log entry
                $objLog->append("[{$strType}] {$strRelpath}");
                // Update the record
                $objModel->found = 1;
                $objModel->hash = $objResource->hash;
                $objModel->save();
            }
        }
        // Check for left-over entries in the DB
        $objFiles = \FilesModel::findByFound('');
        if ($objFiles !== null) {
            $arrMapped = array();
            $arrPidUpdate = array();
            /** @var Model\Collection|FilesModel $objFiles */
            while ($objFiles->next()) {
                $objFound = \FilesModel::findBy(array('hash=?', 'found=2'), $objFiles->hash);
                if ($objFound !== null) {
                    // Check for matching file names if the result is ambiguous (see #5644)
                    if ($objFound->count() > 1) {
                        while ($objFound->next()) {
                            if ($objFound->name == $objFiles->name) {
                                $objFound = $objFound->current();
                                break;
                            }
                        }
                    }
                    // If another file has been mapped already, delete the entry (see #6008)
                    if (in_array($objFound->path, $arrMapped)) {
                        $objLog->append("[Deleted] {$objFiles->path}");
                        $objFiles->delete();
                        continue;
                    }
                    $arrMapped[] = $objFound->path;
                    // Store the PID change
                    if ($objFiles->type == 'folder') {
                        $arrPidUpdate[$objFound->uuid] = $objFiles->uuid;
                    }
                    // Add a log entry BEFORE changing the object
                    $objLog->append("[Moved] {$objFiles->path} to {$objFound->path}");
                    // Update the original entry
                    $objFiles->pid = $objFound->pid;
                    $objFiles->tstamp = $objFound->tstamp;
                    $objFiles->name = $objFound->name;
                    $objFiles->type = $objFound->type;
                    $objFiles->path = $objFound->path;
                    $objFiles->found = 1;
                    // Delete the newer (duplicate) entry
                    $objFound->delete();
                    // Then save the modified original entry (prevents duplicate key errors)
                    $objFiles->save();
                } else {
                    // Add a log entry BEFORE changing the object
                    $objLog->append("[Deleted] {$objFiles->path}");
                    // Delete the entry if the resource has gone
                    $objFiles->delete();
                }
            }
            // Update the PID of the child records
            if (!empty($arrPidUpdate)) {
                foreach ($arrPidUpdate as $from => $to) {
                    $objChildren = \FilesModel::findByPid($from);
                    if ($objChildren !== null) {
                        while ($objChildren->next()) {
                            $objChildren->pid = $to;
                            $objChildren->save();
                        }
                    }
                }
            }
        }
        // Close the log file
        $objLog->close();
        // Reset the found flag
        $objDatabase->query("UPDATE tl_files SET found=1 WHERE found=2");
        // Unlock the tables
        $objDatabase->unlockTables();
        // Return the path to the log file
        return $strLog;
    }

Usage Example

Esempio n. 1
0
 /**
  * {@inheritdoc}
  */
 protected function executeLocked(InputInterface $input, OutputInterface $output)
 {
     $this->framework->initialize();
     $strLog = Dbafs::syncFiles();
     $output->writeln(sprintf('Synchronization complete (see <info>%s</info>).', $strLog));
     return 0;
 }
All Usage Examples Of Contao\Dbafs::syncFiles