125. file system foundation

Posted by fierce at 2020-03-24

In Drupal, file operation is mainly implemented in the way of PHP flow at the bottom. In the early stage of this series, PHP flow is explained in detail, as shown in the following figure:

PHP streams, public files, private files

The system provides a flow wrapper Manager:

Service ID: stream > wrapper > Manager

Class: drupal \ core \ streamwrapper \ streamwrappermanager

It is used to manage all kinds of PHP flow wrappers in a unified way, which is relatively simple and not much to talk about. This article mainly explains the basic operation of curd

File system services:

Container ID: file system

Class: drupal \ core \ file \ filesystem

This service is the file operation class at the bottom of the system. Compared with PHP native file operation function, it supports flow operation, which can be said to be a higher level of encapsulation. Therefore, this class should be used first for file operation in Drupal. Because it supports flow wrapper, the path is also collectively referred to as URI. This class belongs to the bottom operation, so it does not involve hook execution, etc


$file_system = \Drupal::service('file_system'); $fileDir = "public://yunke/2019/"; //保存文件到一个公有目录 $dirOK = $file_system-prepareDirectory($fileDir, 1);//确保目录存在且可写 if (!$dirOK) { echo "不能新建目录,或无写权限"; die; } $filePath = rtrim($fileDir, '/\\') . "/test.txt"; //文件路径, $filePath = $file_system-saveData("这是一个测试", $filePath);//保存数据到文件 if ($filePath) { echo "已经成功保存数据到文件:" . $filePath; } die;

Run the above code in the controller to write the file in the public file directory, usually:


The address of the public file directory depends on the site configuration. It is specified in the configuration file with the "file public path" item. It can be saved repeatedly. Each time you save, a new file will be created, and the file name will be incremented with a number suffix. Next, we will introduce the method of file system service.

Method introduction:

public function moveUploadedFile($filename, $uri)

Move the uploaded temporary file to a new location. Compared with PHP's native move ﹣ uploaded ﹣ file function, this method supports flow wrapper. The first parameter is the full path name of the temporary file, the second is the target path, which can be the flow path, and returns a Boolean value to identify whether it is successful or not

public function chmod($uri, $mode = NULL)

Set the permissions of the file or directory, $mode is optional. If it is not passed, it will be obtained from the following items in the configuration file:

"File? Chmod? Directory" (the default is "0775")

"File? Chmod? File" (file permission, default is "0664")

Returns a Boolean value. The log will be recorded in case of failure. Whether the flow wrapper is supported depends on how the flow wrapper is implemented

public function unlink($uri, $context = NULL)

Delete a file, support stream wrapper, return Boolean value, delete read-only file in window system

public function realpath($uri)

Get a URI normalized absolute path name (handle symbolic links and relative path symbols), similar to the PHP native function realpath, but support flow wrapper, do not support remote files, there is no symbolic connection in the returned path, '/. /' or '/.. /' Component, there is no '/' at the end. In the window system, the path separator '\' will not be replaced by '/', and errors will occur when it is used for non-existent files, but the directory will not

public function dirname($uri)

Return the directory name of the path, similar to PHP's dirname function, but supports flow wrapper, with no slash at the end

public function basename($uri, $suffix = NULL)

Get the file name of the file, which can be used for non-existent files. The parameter $suffix is usually the extension with dot number. If it is passed, the file name will be removed before returning. Stream wrapper and non us-ascii characters are supported

public function mkdir($uri, $mode = NULL, $recursive = FALSE, $context = NULL)

$URI: directory path

$mode: permission ID, if not passed, will be obtained from the configuration file

$recursive: whether to create recursively, that is, whether to create automatically when the parent directory does not exist. The default is false

$context: create context, default to null, see PHP native MKDIR function for details

If it is a flow wrapper path, delegate to the flow wrapper creation; return Boolean value, and return false when the permission cannot be created or set

public function rmdir($uri, $context = NULL)

Delete a directory. Non empty directories cannot be deleted successfully. Stream wrapper is supported. Read only files of windows system will be processed correctly

public function tempnam($directory, $prefix)

Similar to PHP native tempnam function, but supports stream wrapper. It determines a unique file name in the specified directory and creates a file, and then returns its full path file name. You can specify the file name prefix (only the first three characters of the transfer prefix will be used in the window system). If the transfer directory does not exist, a file will be generated in the temporary directory of the system and returned. If it fails, it will be returned Back to false

public function uriScheme($uri)

Return the URI protocol. If not, return false. For example, "scheme: / / target" returns "scheme". In a special case, "data: target" will return "data". In particular, the protocol "data" does not use ": / /" as the separator

public function validScheme($scheme)

$destination: copy target, which can be directory name or file name. Full path must be provided. If it is directory, the original file name will be used.

$replace: processing behavior when the target already has a file with the same name (see getdestinationfilename method for details): replace, rename, and prompt for errors.

If the copy is successful, the full pathname of the target file will be returned. If the copy is unsuccessful, the log will be logged and an exception will be thrown

public function delete($path)

It is used to delete a file and returns true if it succeeds. If it fails, the log will be recorded and an exception will be thrown. It is not supported to delete the directory (instead of deleterecursive). If you delete a file that does not exist, the log will be recorded and true will be returned

public function deleteRecursive($path, callable $callback = NULL)

Recursively delete a directory or file. Optionally, transfer a callback function, which will be called on each file path and directory path. The callback function has only one parameter, which is used to receive the full path of the file or directory. The callback is usually used to change the database record in linkage. The operation time is before the file is deleted or before the directory is traversed. The method ignores the return value of the callback, so it returns Call cannot prevent delete operation. If modify permission is used to block, an exception will be thrown in subsequent delete operation

The main process is exactly the same as the copy operation, except that this method is a move operation (cut). If the call of the native move operation fails internally, the copy will be adopted, and then the original file will be deleted, which will support cross protocol operation; the move file and directory (non empty directory can also be used), and the destination address will be returned if successful

There is a non-public protected method to prepare the target path for the move or copy operation. It will check the existence of the source path, whether it is the same as the target path, various permission problems, replacement disabled characters, utf8 character set, and save the htaccess file. According to the replacement settings, the target path may change, so it is received by reference. If the method does not throw an exception, it indicates that Target path available (possibly modified)

public function saveData($data, $destination, $replace = self::EXISTS_RENAME)

Save the data to a file, write the data to a temporary file internally, and then move it to the target address. The first parameter is the content of the file. If it succeeds, the target address will be returned. If it fails, an exception will be thrown

public function prepareDirectory($directory, $options = self::MODIFY_PERMISSIONS)


(the constant value is 2. If the permission is not writable, it can be modified to writable, but it will not be created if it does not exist.)


(the constant value is 1, which means it is created recursively if it does not exist, and the permissions set in the configuration file are used.)

Internally: if the result of the operation "" with 1 is false, it will not be created when the directory does not exist, and false will be returned. Otherwise, it will be created recursively. If the result of the operation "" with 2 is false, it will not be corrected when the directory is not writable, otherwise it will change the permissions to the default permissions specified in the configuration file. Only when true is returned, the caller should continue Continued operation.

public function getDestinationFilename($destination, $replace)

According to the existence of the target file and the configuration of the replacement behavior, return the full path of the processed target file. There are three replacement behaviors:

\Drupal \ core \ file \ filesystemminterface:: exists_replace (value 1)

\Drupal \ core \ file \ filesystemminterface:: exists \ rename (value 0)

\Drupal \ core \ file \ filesystemminterface:: exists_error (value 2)

If it doesn't exist, it will return as is. This method will check whether the filename is a valid utf8 character. If it doesn't, an error will be thrown

public function createFilename($basename, $directory)

This method will determine the full path of a file to ensure that it does not exist (it will not be automatically created). The parameter $basename is the file name with extension, without path, and the parameter $directory is the directory path (optional backslash). If the file name passed in exists, it will be incremented by increasing the sequence number, an integer starting from 0. If "Yunke. PHP" exists, it will be changed to "yunke_0. PHP" ”, if it still exists, it will be changed to "yunke_1. PHP", which will be incremented until it doesn't exist, and then the full new filename with path will be returned; if it is a Windows operating system, then in the filename: ':', '*', '?', '"', '', '', ',' | 'will be replaced with a underline, and then the existence of the file will be determined

Note: when adding the serial number, the extension is separated by the last point number. If the extension itself has a point number, it may not be the desired result, such as the information file of Drupal module: "Yunke. Info. YML" may be "Yunke. Info _0. YML"

File mimeType guesser:

Used to give a file name (with path) and return its file MIME type ID

Service ID: file.mime_type.guess

Class: \ drupal \ core \ file \ mimeType \ mimeType guess


$mimeType = \Drupal::service('file.mime_type.guesser')-guess($path);

Strictly speaking, this service should be called the manager or agent of "file mimeType guessing machine", because it does not perform guessing itself, but automatically collects the defined guessing machine services in the system, and executes them according to the priority. If the high priority guessing machine returns null, it will try the next low priority guessing machine. If it returns other values (including false), it will end up Stop guessing and return as the result. By default, the system provides a guessing machine with extension:

Extension file mimeType guesser:

Service ID: file.mime_type.guess.extension

Class: \ drupal \ core \ file \ mimeType \ extensionmimetype guess

Based on the extension, the guesser looks up the MIME type ID in the predefined list. If it cannot find it, it will return the following default values:


This means that a MIME type identifier must be returned for the file. The module can perform the following modification hooks to add a modification predefined list:


Modify the hook to receive an array. The format is as follows:


There are two key names:

"Mimetypes": save number to MIME type identity mapping

"Extensions": save extension to number mapping

The number is optional, but it needs to be consistent. The extension can be multi-level extension with dot number, and it must be lowercase

Custom guesser

To customize the guesser, you can define a class that implements the following interfaces:

Define it as a service, and give the service tag: "mime" type "and priority. The recompile container will be collected automatically


$fileName=iconv('UTF-8', 'GBK//IGNORE', $fileName);

However, it is generally recommended to use or convert filename to iso-8859-1 character set, such as transliteration conversion, hash value, date plus sequence number, etc