Yii2 init 初始化指令碼分析

唐青枫發表於2024-10-27

指令碼目的:

init 指令碼主要的作用是:從 environments 目錄中複製配置檔案,確保應用適配不同環境(例如開發、生產環境等)。

工作流程:

  • 獲取 $_SERVERargv 引數
  • 載入 environments/index.php 檔案,拿到不同環境配置指定的配置檔案關係。
  • 如果執行 init 指令碼時提供了 --env 選項,例如:--env=Development 則直接應用此環境,否則會被提示需要選擇一個環境來初始化。
  • 獲取 environments 對應環境下的所有檔案。
  • 因為上一步獲取到的所有檔案是帶有檔案全路徑的,所以這一步直接複製檔案到對應的路徑,如:frontend/config/params-local.php
  • environments/index.php 檔案中獲取到對應環境所配置的需要設定可寫、可執行的目錄來執行操作。

程式碼詳解:

  • 解析命令列引數:

  • 檢查命令列引數:

  • 獲取 environments 中的檔案列表:

  • 複製檔案:
function copyFile($root, $source, $target, &$all, $params)
{
    // 檢查原始檔是否存在
    if (!is_file($root . '/' . $source)) {
        echo "       skip $target ($source not exist)\n";
        return true;
    }
    // 檢查目標檔案是否存在
    if (is_file($root . '/' . $target)) {
        if (file_get_contents($root . '/' . $source) === file_get_contents($root . '/' . $target)) {
            echo "  unchanged $target\n";
            return true;
        }
        // 如果$all為true,輸出資訊並直接進行覆蓋。
        // 否則,提示使用者目標檔案已存在,並詢問是否覆蓋(選擇“是”、“否”、“全部”或“退出”)。
        if ($all) {
            echo "  overwrite $target\n";
        } else {
            echo "      exist $target\n";
            echo "            ...overwrite? [Yes|No|All|Quit] ";


            // 透過命令列接收使用者輸入。如果$params['overwrite']不為空,使用該值;否則,等待使用者輸入。
            $answer = !empty($params['overwrite']) ? $params['overwrite'] : trim(fgets(STDIN));

            // 根據使用者輸入執行相應操作:
            // 如果輸入“q”或“Q”,返回false以退出操作。
            // 如果輸入“y”或“Y”,輸出覆蓋資訊並繼續。
            // 如果輸入“a”或“A”,輸出覆蓋資訊並設定$all為true,以便後續檔案均自動覆蓋。
            // 其他輸入則跳過目標檔案。
            if (!strncasecmp($answer, 'q', 1)) {
                return false;
            } else {
                if (!strncasecmp($answer, 'y', 1)) {
                    echo "  overwrite $target\n";
                } else {
                    if (!strncasecmp($answer, 'a', 1)) {
                        echo "  overwrite $target\n";
                        $all = true;
                    } else {
                        echo "       skip $target\n";
                        return true;
                    }
                }
            }
        }
        file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
        return true;
    }
    // 如果目標檔案不存在,輸出資訊並進行復制。
    echo "   generate $target\n";
    // 使用@mkdir建立目標檔案的目錄(如果不存在),並設定目錄許可權為0777。
    @mkdir(dirname($root . '/' . $target), 0777, true);
    file_put_contents($root . '/' . $target, file_get_contents($root . '/' . $source));
    return true;
}
  • 執行回撥方法:
$callbacks = ['setCookieValidationKey', 'setWritable', 'setExecutable', 'createSymlink'];
foreach ($callbacks as $callback) {
    if (!empty($env[$callback])) {
        $callback($root, $env[$callback]);
    }
}
// 讀取 environments/index.php 檔案的配置:
'Development' => [
    'path' => 'dev',
    'setWritable' => [ // runtime目錄設定為可寫
        'backend/runtime',
        'console/runtime',
        'frontend/runtime',
    ],
    'setExecutable' => [ // yii、yii_test檔案設定為可執行
        'yii',
        'yii_test',
    ],
    'setCookieValidationKey' => [
        'backend/config/main-local.php',
        'common/config/codeception-local.php',
        'frontend/config/main-local.php',
    ],
],

// 執行具體的回撥方法:
// 設定檔案可寫
function setWritable($root, $paths)
{
    foreach ($paths as $writable) {
        if (is_dir("$root/$writable")) {
            if (@chmod("$root/$writable", 0777)) {
                echo "      chmod 0777 $writable\n";
            } else {
                printError("Operation chmod not permitted for directory $writable.");
            }
        } else {
            printError("Directory $writable does not exist.");
        }
    }
}

// 設定檔案可執行
function setExecutable($root, $paths)
{
    foreach ($paths as $executable) {
        if (file_exists("$root/$executable")) {
            if (@chmod("$root/$executable", 0755)) {
                echo "      chmod 0755 $executable\n";
            } else {
                printError("Operation chmod not permitted for $executable.");
            }
        } else {
            printError("$executable does not exist.");
        }
    }
}

function setCookieValidationKey($root, $paths)
{
    foreach ($paths as $file) {
        echo "   generate cookie validation key in $file\n";
        $file = $root . '/' . $file;
        $length = 32;
        $bytes = openssl_random_pseudo_bytes($length);
        $key = strtr(substr(base64_encode($bytes), 0, $length), '+/=', '_-.');
        $content = preg_replace('/(("|\')cookieValidationKey("|\')\s*=>\s*)(""|\'\')/', "\\1'$key'", file_get_contents($file));
        file_put_contents($file, $content);
    }
}

相關文章