Laravel 常見問題: Specified key was too long

Laravel 在 5.4 版之後為了支援 emoji , 因此將資料編碼改為 utf8mb4. 由於 utf8mb4 的儲存空間需求膨脹了4倍, 導致預設長度無法正常寫入資料庫.

這個問題會在 MySQL 5.7.6 以下與 MariaDB 的環境中出現以下錯誤

[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1071 Specified key was too long; max key length is 767 bytes

在 Migrate 過程中出現這個問題的解決方法有兩種

  1. 更新到 MySQL 5.7.7 以上版本
  2. 調整 Laravel 的預設資料長度

升級 MySQL 的方法就不細說了, 接下來主要說明調整 Laravel 預設值的方法

首先, 編輯專案目錄下的 app/Providers/AppServiceProvider.php

新增一個引用

use Illuminate\Support\Facades\Schema;

接著修改 boot function, 將預設長度定為 191

public function boot()
{
    Schema::defaultStringLength(191);
}

重新執行 php artisan migrate 就不會有問題了

最後附上完整的 AppServiceProvider.php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        Schema::defaultStringLength(191);
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

將 MAC 內建的 PHP 5.6 升級到 PHP 7

在 MAC 上進行開發時使用的是 MAC 內建 PHP 5.6, 但 PHP 7 實在是很好用, 決定把 MAC 的 PHP 5.6 升級成 PHP 7, Mac 上要升級到 PHP 7非常簡單, 國外已經有人提供編譯好的版本與安裝腳本, 使用起來非常容易

相關資料

官方網站 php-macosx

安裝 PHP 7

選擇一個想要安裝的 PHP 版本, 目前支援 PHP 7.0 與 PHP 7.1

選擇 PHP 7.0

curl -s http://php-osx.liip.ch/install.sh | bash -s 7.0

選擇 PHP 7.1

curl -s http://php-osx.liip.ch/install.sh | bash -s 7.1

測試結果

接著寫入一個 phpinfo

<?php phpinfo();

看到下面這個畫面就代表我們成功升級為 PHP 7 了!

調整 Apache 設定

由於 MAC 預設使用 PHP 5, MAC 內建的 Apache 的 PHP 解釋器預設是連結到 libphp5.so, 當安裝新的 PHP 7 之後會產生衝突, 因此我們必須關閉舊版的模組, Apache 才能正常運作

關閉 PHP 5 模組

編輯 httpd.conf

sudo vim /etc/apache2/httpd.conf

找到原先的 libphp5.so 模組

LoadModule php5_module libexec/apache2/libphp5.so

在前面加上 # 將其註解

#LoadModule php5_module libexec/apache2/libphp5.so

重新啟動 Apache

sudo apachectl restart

Laravel 電話長度與選填欄位的實作筆記

最近在處理計畫的網站, 計畫的網站當中有一個選填電話的欄位, 在使用 Laravel 內建 Validation 進行長度檢查時意外踩到坑, 仔細查閱手冊後才發現 Max, Min 的行為與心中所有有所差距, 因此做個筆記避免往後夥伴踩到一樣的坑

Laravel 的 Validation 非常強大, 若要讓欄位選填並且只有在有填寫內容時才進行其他驗證, 可以使用內建的 nullable 達到效果, 而不需要使用 required

$rules = [ 'phone'=>'nullable' ];

針對數字的部分可以用 numeric 來達到驗證

$rules = [ 'phone'=>'nullable|numeric' ];

在長度檢查的部分我一開始是用了 min 與 max 來檢查, 結果無論如何都會觸發長度過長的錯誤, 仔細看過手冊後發現 Laravel 會去猜輸入的型別, 如果猜測結果是數字則 min, max 會變成比大小(min < x < max) 而不是預期的長度檢查, 正確長度檢查要使用 digits_between 這個規則才對

$rules = [ 'phone'=>'nullable|numeric|digits_between:10,12' ];

不用懶人包在 MAC 上安裝 Apache, PHP, MySQL

當我們需要在 Mac 下進行網站開發時, 時常會用到 Apache, PHP, MySQL (AMP) 組合, 在 Windows 下常見的懶人包有 XAMPP, Appserv…等, 雖然 Mac 也有懶人包像是 MAMP, 但實際上 MAC 已經內建了 Apache 與 PHP , 並不需要用到懶人包, 我們只需要設定一下就可以啟動他們.

提醒

由於許多操作涉及管理員權限, 因此指令都有加上 sudo, 過程中如有詢問密碼若無特別說明則為您的 mac 使用者密碼

啟動 Apache

啟動內建的 Apache

sudo apachectl start

當我們啟動 Apache 後, 便可以訪問一下 http://127.0.0.1 檢查一下是否有正常運作

如果畫面上出現 It Works 就代表我們成功啟動 Apache 了!

整合 PHP

由於 Mac 已經內建 PHP 模組, 我們只要在 Apache 中將他啟用就可以了

使用編輯器編輯 Apache 設定檔

/etc/apache/httpd.conf

找到下面這行將前面的 # 刪除

#LoadModule php5_module libexec/apache2/libphp5.so

重新啟動 Apache

sudo apachectl restart

步驟做完了, 當然要驗證一下 PHP 是否有如期運作, 透過下面指令建立一個測試用的 php 檔案

echo "<?php phpinfo();" | sudo tee /Library/WebServer/Documents/info.php

接著我們就可以瀏覽 http://127.0.0.1/info.php 檢查一下結果

如果出現如上圖的畫面就代表 PHP 已經正常啟動了!(PHP Info 可能會因為版本不同而有些微差異)

安裝 MySQL

由於 Mac 並沒有內建 MySQL, 因此我們需要自己從官方網站下載來安裝
https://dev.mysql.com/downloads/mysql/

使用 DMG 封裝的版本進行安裝

點選下載後會出現要你登入的頁面, 但其實可以直接點選下面的 No thanks, just start my download. 直接進行下載

安裝過程的最後一步會跳出一個臨時密碼的視窗, 我們要記住這個密碼, 後續設定會用到

接著打開 Mac 的系統設定, 左下角會多出一個 MySQL 的選項, 點開 MySQL 進行設定

剛安裝完成 MySQL 並不會啟動, 我們需要手動點選 Start MySQL Server(爾後電腦重開會自動啟動)

當狀態轉變為 running 就代表啟動成功

啟動 Mysql 後, 接著要修改 root 密碼

/usr/local/mysql/bin/mysqladmin -uroot -p password '新的密碼'

指令執行期間會提示輸入 root 密碼, 這時候要輸入的密碼是安裝完成後出現的那組臨時密碼

這樣 Apache + PHP + MySQL (AMP) 的開發環境就建立完成啦!

工作目錄權限調整

Mac 的 Apache 預設工作目錄為

/Library/WebServer/Documents/

由於預設的擁有者是 root, 這會導致我們無法直接寫入檔案, 可以透過以下指令將所有權變成你的

sudo chown -R 你的mac使用者 /Library/WebServer/Documents/

在 Debian 8 上安裝 Nginx + PHP7-FPM

Nginx 在 Web Server 領域有著極為優異的表現, 如果搭配 PHP-FPM 可以讓網站的速度更上一層樓, 本篇文章將與各位分享如何在 Debian 8 上安裝 Nginx 與 PHP-FPM

環境資訊

Debian 8 (Jessie) 請注意OS版本, 本文針對 Debian 8 做說明
Nginx 1.6.2
PHP 7.0

安裝 nginx

sudo apt-get install nginx -y

安裝 PHP7-FPM

本文章為濃縮版, 指令細節可以參考 在 Debian 8 (Jessie) 上安裝 Apache + PHP 7

echo "deb http://mirrors.teraren.com/dotdeb/ stable all" | sudo tee --append /etc/apt/sources.list
echo "deb-src http://mirrors.teraren.com/dotdeb/ stable all" | sudo tee --append /etc/apt/sources.list
wget -qO - https://www.dotdeb.org/dotdeb.gpg | sudo apt-key add -
sudo apt-get update && sudo apt-get upgrade -y
sudo apt-get install php7.0-fpm php7.0-common -y
sudo apt-get install php7.0-zip php7.0-mysql php7.0-mcrypt php7.0-mbstring php7.0-json php7.0-imagick php7.0-gmp php7.0-curl php7.0-dom php7.0-gd -y

調整 PHP-FPM 設定

我們必須調整 php 的設定, 使得 php 更加安全

sudo vim /etc/php/7.0/fpm/php.ini

將本來由 ;註解掉的設定

;cgi.fix_pathinfo=1

修改為

cgi.fix_pathinfo=0

重新啟動 PHP-FPM

sudo systemctl restart php7.0-fpm

連接 Nginx 與 PHP

sudo vim /etc/nginx/sites-available/default

將下方設定檔寫入其中

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;
    index index.html index.htm index.php index.nginx-debian.html;

    server_name _;

    location / {
        try_files $uri $uri/ =404;
    }

        location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
    }
}

重新啟動 Nginx

sudo systemctl restart nginx

測試

將測試用檔案寫入 Nginx 預設目錄

echo "<?php phpinfo();" | sudo tee /var/www/html/info.php

打開瀏覽器前往 http://你的IP/info.php


當你看到這個畫面就代表PHP成功運行, 紅框的部分顯示 FPM/FastCGI 代表我們的 PHP 確實是使用 PHP-FPM 模式運行

由於 phpinfo 會透露很多詳細資訊, 為了安全起見, 欣賞完畢要順手把 info.php 刪除

sudo rm /var/www/html/info.php

如何在 XAMPP 3 安裝 XDebug

XDebug 是 PHP 一個很好用的除錯工具, 同時也是Unit Test 的好幫手, 做好 UnitTest Coverage 就靠它了!

今天在處理 XAMPP 測試環境時發現 XAMPP 3 的 XDebug 設定不見了, 於是花點時間把它找了出來, 在這邊記錄一下如何在 XAMPP 啟動 XDebug 的方法

環境

XAMPP v3.2.2
Windows 10

Step 1. 停止 Apache

我們可以藉由 XAMPP Control Panel 先將 Apache 停止

Step 2. 修改 PHP.ini

從 XAMPP Control Panel 中快速開啟 php.ini

並將下列內容貼到 php.ini 的底部並存檔
請記得將 S:\xampp 更換為 XAMPP 實際安裝位置

[XDebug]
zend_extension = "S:\xampp\php\ext\php_xdebug.dll"
xdebug.profiler_append = 0
xdebug.profiler_enable = 1
xdebug.profiler_enable_trigger = 0
xdebug.profiler_output_dir = "S:\xampp\tmp"
xdebug.profiler_output_name = "cachegrind.out.%t-%s"
xdebug.remote_enable = 0
xdebug.remote_handler = "dbgp"
xdebug.remote_host = "127.0.0.1"
xdebug.trace_output_dir = "S:\xampp\tmp"

Step 3. 啟動 Apache

Step 4. 確認 XDebug 正常載入

如果 XDebug 有正常載入, 我們便可以在 phpinfo 中看到相關資訊

小記

在 XAMPP 3 之前, XDebug 的設定都已經幫我們寫好在 php.ini 裡, 只是被註解掉了, 但 XAMPP 3 之後就消失, 讓我還特地去挖設定檔

open_basedir 繞過

在多使用者或者設定較為嚴格的環境中, 管理者會在 php.ini 中指定 open_basedir 來避免目錄存取越界, 但實際上 open_basedir 這個參數在某些狀況下是無效的, 是可以技巧性的繞過

熟悉 php 開發的人應該都會知道 glob 這個函數, glob 函數實際上是不受到 open_basedir 影響, 可以取得限制外的資訊, 解決辦法就只要將其禁用即可, 但除了 glob 這個函數外還有另一種方法.

方法

在 php5 以上 有一個 Class: DirectoryIterator, 我們可以藉由這個類別與 glob:// 來再次繞過 open_basedir

Code:

$files = [];
$glob = new DirectoryIterator("glob:///*");
foreach($glob as $f) {
    $files[] = $f->__toString();
}