In Yii 2.0, when creating a multi-level directory based on FileHelper, an error is reported: chmod(): operation not permitted, which in turn can only successfully create one level analysis and solution at a time.
1. When uploading the topic selection material, the server is internally wrong. as shown in Figure 1
{
"name": "Internal Server Error",
"message": "服务器内部错误。",
"code": 0,
"status": 500
}
2. Decided to adjust to the development mode (dev), upload the topic selection material again to view more detailed error information, report error: chmod(): operation not permitted, as shown in Figure 2
{
"name": "Exception",
"message": "Failed to change permissions for directory \"/webtv/wangjie/pcs-api/tmp/2019/12/05\": chmod(): Operation not permitted",
"code": 2,
"type": "yii\\base\\Exception",
"file": "/mcloud/www/pcs-api/vendor/yiisoft/yii2/helpers/BaseFileHelper.php",
"line": 635,
"stack-trace": [
"#0 /mcloud/www/pcs-api/common/services/AssetService.php(77): yii\\helpers\\BaseFileHelper::createDirectory('/webtv/wangjie/...')",
"#1 /mcloud/www/pcs-api/api/rests/asset/UploadAction.php(93): common\\services\\AssetService::uploadTempAssets(Array)",
"#2 [internal function]: api\\rests\\asset\\UploadAction->run()",
"#3 /mcloud/www/pcs-api/vendor/yiisoft/yii2/base/Action.php(94): call_user_func_array(Array, Array)",
"#4 /mcloud/www/pcs-api/vendor/yiisoft/yii2/base/Controller.php(157): yii\\base\\Action->runWithParams(Array)",
"#5 /mcloud/www/pcs-api/vendor/yiisoft/yii2/base/Module.php(528): yii\\base\\Controller->runAction('upload', Array)",
"#6 /mcloud/www/pcs-api/vendor/yiisoft/yii2/web/Application.php(103): yii\\base\\Module->runAction('v1/asset/upload', Array)",
"#7 /mcloud/www/pcs-api/vendor/yiisoft/yii2/base/Application.php(386): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))",
"#8 /mcloud/www/pcs-api/api/web/index.php(17): yii\\base\\Application->run()",
"#9 {main}"
],
"previous": {
"name": "PHP Warning",
"message": "chmod(): Operation not permitted",
"code": 2,
"type": "yii\\base\\ErrorException",
"file": "/mcloud/www/pcs-api/vendor/yiisoft/yii2/helpers/BaseFileHelper.php",
"line": 633,
"stack-trace": [
"#0 [internal function]: yii\\base\\ErrorHandler->handleError(2, 'chmod(): Operat...', '/mcloud/www/pcs...', 633, Array)",
"#1 /mcloud/www/pcs-api/vendor/yiisoft/yii2/helpers/BaseFileHelper.php(633): chmod('/webtv/wangjie/...', 509)",
"#2 /mcloud/www/pcs-api/common/services/AssetService.php(77): yii\\helpers\\BaseFileHelper::createDirectory('/webtv/wangjie/...')",
"#3 /mcloud/www/pcs-api/api/rests/asset/UploadAction.php(93): common\\services\\AssetService::uploadTempAssets(Array)",
"#4 [internal function]: api\\rests\\asset\\UploadAction->run()",
"#5 /mcloud/www/pcs-api/vendor/yiisoft/yii2/base/Action.php(94): call_user_func_array(Array, Array)",
"#6 /mcloud/www/pcs-api/vendor/yiisoft/yii2/base/Controller.php(157): yii\\base\\Action->runWithParams(Array)",
"#7 /mcloud/www/pcs-api/vendor/yiisoft/yii2/base/Module.php(528): yii\\base\\Controller->runAction('upload', Array)",
"#8 /mcloud/www/pcs-api/vendor/yiisoft/yii2/web/Application.php(103): yii\\base\\Module->runAction('v1/asset/upload', Array)",
"#9 /mcloud/www/pcs-api/vendor/yiisoft/yii2/base/Application.php(386): yii\\web\\Application->handleRequest(Object(yii\\web\\Request))",
"#10 /mcloud/www/pcs-api/api/web/index.php(17): yii\\base\\Application->run()",
"#11 {main}"
]
}
}
3. View the mounted directory, /webtv/wangjie/pcs-api/tmp/2019/12/05, the connection has been uploaded 2 times, and the first time has been generated: 12, 2 The secondary generated directory: 05, as shown in Figure 3
[root@d48dedd9fceb pcs-api]# ls
2019 tmp
[root@d48dedd9fceb pcs-api]# cd tmp
[root@d48dedd9fceb tmp]# ls
2019
[root@d48dedd9fceb tmp]# cd 2019
[root@d48dedd9fceb 2019]# ls
10 11 12
[root@d48dedd9fceb 2019]# cd 12
[root@d48dedd9fceb 12]# ls
05
[root@d48dedd9fceb 12]# cd 05
[root@d48dedd9fceb 05]# ls
[root@d48dedd9fceb 05]# pwd
/webtv/wangjie/pcs-api/tmp/2019/12/05
[root@d48dedd9fceb 05]# ls -l
total 0
[root@d48dedd9fceb 05]# cd ..
[root@d48dedd9fceb 12]# ls -l
total 0
drwxrwxrwx 2 root root 0 Dec 5 15:28 05
[root@d48dedd9fceb 12]#
4. Analyze the reasons. The current user is nginx, the user who view the directory in the development environment, and in the error-reporting environment, the user of the directory is root, and the mode is 0777, the current user refers to the user who executes php. It is likely that it is not the same as the usual shell or ftp user. File mode can only be changed by the user of the file owner in most systems. as shown in Figure 4
[root@685b4b7fd197 /]# cd /webtv/wangjiedev/pcs-api/
[root@685b4b7fd197 pcs-api]# ls
2019 php-fpm1.conf php-fpm.conf tmp
[root@685b4b7fd197 pcs-api]# cd tmp
[root@685b4b7fd197 tmp]# ls -l
total 0
drwxrwxr-x 9 nginx nginx 101 Dec 2 16:26 2019
5. In the end, it is decided to continue the class: yii\helps\FileHelper, overwrite the static method: createdirectory($path, $mode = 0775, $recursive = true), when chmod() fails to change the file mode, returns true, does not throw an exception, continues the subsequent execution, create a new class: \common\helpers\filehelper.php
* @since 1.0
*/
class FileHelper extends \yii\helpers\FileHelper
{
/**
* Creates a new directory.
*
* This method is similar to the PHP `mkdir()` function except that
* it uses `chmod()` to set the permission of the created directory
* in order to avoid the impact of the `umask` setting.
*
* @param string $path path of the directory to be created.
* @param int $mode the permission to be set for the created directory.
* @param bool $recursive whether to create parent directories if they do not exist.
* @return bool whether the directory is created successfully
* @throws \yii\base\Exception if the directory could not be created (i.e. php error due to parallel changes)
*/
public static function createDirectory($path, $mode = 0775, $recursive = true)
{
if (is_dir($path)) {
return true;
}
$parentDir = dirname($path);
// recurse if parent dir does not exist and we are not at the root of the file system.
if ($recursive && !is_dir($parentDir) && $parentDir !== $path) {
static::createDirectory($parentDir, $mode, true);
}
try {
if (!mkdir($path, $mode)) {
return false;
}
} catch (\Exception $e) {
if (!is_dir($path)) {// https://github.com/yiisoft/yii2/issues/9288
throw new \yii\base\Exception("Failed to create directory \"$path\": " . $e->getMessage(), $e->getCode(), $e);
}
}
try {
return @chmod($path, $mode);
} catch (\Exception $e) {
throw new \yii\base\Exception("Failed to change permissions for directory \"$path\": " . $e->getMessage(), $e->getCode(), $e);
}
}
}
6. When creating the directory later, all refer to the newly created class: Common\Helpers\FileHelper, enter the error environment, manually delete the directory: /webtv/wangjie/pcs-api/tmp/2019/12, as shown in Figure 5
7. Upload the topic selection material again, and report an error: “Create directory: /webtv/wangjie/pcs-api/tmp/2019/12/05, failed”, as shown in Figure 6
{
"name": "Internal Server Error",
"message": "创建目录:/webtv/wangjie/pcs-api/tmp/2019/12/05,失败",
"code": 202002,
"status": 500,
"type": "yii\\web\\ServerErrorHttpException"
}
8. Check the mounted directory, /webtv/wangjie/pcs-api/tmp/2019/12/05, the first time has been created successfully, it has been determined that the problem that multiple directories cannot be created at one time has been solved, as shown in Figure 7
9. The reason for the analysis is that the static method: CreateDirectory($PATH, $MODE = 0775, $recursive = true), not returned True, which leads to the judgment that the creation of the directory fails and throws an exception, so no matter what the chmod result is, it returns true
* @since 1.0
*/
class FileHelper extends \yii\helpers\FileHelper
{
/**
* Creates a new directory.
*
* This method is similar to the PHP `mkdir()` function except that
* it uses `chmod()` to set the permission of the created directory
* in order to avoid the impact of the `umask` setting.
*
* @param string $path path of the directory to be created.
* @param int $mode the permission to be set for the created directory.
* @param bool $recursive whether to create parent directories if they do not exist.
* @return bool whether the directory is created successfully
* @throws \yii\base\Exception if the directory could not be created (i.e. php error due to parallel changes)
*/
public static function createDirectory($path, $mode = 0775, $recursive = true)
{
if (is_dir($path)) {
return true;
}
$parentDir = dirname($path);
// recurse if parent dir does not exist and we are not at the root of the file system.
if ($recursive && !is_dir($parentDir) && $parentDir !== $path) {
static::createDirectory($parentDir, $mode, true);
}
try {
if (!mkdir($path, $mode)) {
return false;
}
} catch (\Exception $e) {
if (!is_dir($path)) {// https://github.com/yiisoft/yii2/issues/9288
throw new \yii\base\Exception("Failed to create directory \"$path\": " . $e->getMessage(), $e->getCode(), $e);
}
}
try {
// return chmod($path, $mode);
@chmod($path, $mode);
return true;
} catch (\Exception $e) {
throw new \yii\base\Exception("Failed to change permissions for directory \"$path\": " . $e->getMessage(), $e->getCode(), $e);
}
}
}
10. Manually delete the directory: /webtv/wangjie/pcs-api/tmp/2019/12, upload the topic selection material again, the uploaded resource is successful, in line with expectations, as shown in Figure 8
11. View the mounted directory, /webtv/wangjie/pcs-api/tmp/2019/12/05/15755537845.5862.1232301337.jpg Already exists and meets expectations, as shown in Figure 9








