本文主要內容翻譯自《macOS 10.12 Sierra Apache Setup: Multiple PHP Versions》,並加入了本身的實踐。php
前言:每次搭建開發環境真的是一件很麻煩的事情,但隨着時間的推移和系統環境的差別,網上的教程本身曾經安裝的經驗常常不合時宜,總會出現一些這樣或那樣的問題。經過幾番搜尋,我終於找到一篇完善的教程,將其翻譯成了中文。我也會持續更新這篇文章,不斷完善並記錄遇到的或新或舊的問題。但願這篇文章能夠終結在 macOS 上安裝 PHP 開發環境的話題。html
關於如何在 macOS 10.12 上搭建 Web 開發環境,原做者一共寫了三篇文章。這是第一篇。python
當前的操做系統是 macOS 10.12,這篇教程講述的環境搭建和通常 PHP 安裝最大的不一樣是,咱們不使用系統自帶的 Apache(macOS 自帶了 apache、python、ruby 等一些列開發工具),而是使用 Homebrew 的 Apache。固然,系統自帶的 Apaceh 也是能夠工做的。mysql
在 macOs 上進行 Web 開發,確實是一件很使人愉快的事情。目前也有不少集成開發工具能夠方便地搭建開發環境,好比 MAMP PRO,它具備很是漂亮的一個 UI 界面,而且集成了 Apache、PHP 和 MySQL 三個軟件,很是適合新手使用。可是有時候,因爲其配置模板有限,軟件沒有及時升級,使用它的時候可能會遇到軟件版本不能及時更新、配置不夠方便靈活等問題。nginx
因而不少人就開始尋找替代方案。幸運的是,這篇文章就是一個替代方案。而且文章給出了簡單直接的安裝配置步驟。git
如下全部軟件的安裝都依賴於 macOS 上的一個包管理工具 Homebrew。使用 brew
命令,咱們能夠方便地在 mac 上安裝各類功能各異的軟件,固然,首先的安裝 homebrew。安裝步驟也很是簡單,打開終端而後輸入下面的代碼:github
$ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
而後等待終端提示你輸入密碼,程序就會開始自動安裝。若是你沒有安裝 XCode Command Line Tools
,它會自動幫你裝上。等待幾分鐘,待完成後,就可使用下面的命令查看 Homebrew 是否正確安裝:web
$ brew --version Homebrew 1.1.5 Homebrew/homebrew-core (git revision a50a6; last commit 2016-12-28)
同時可能你也須要執行一下下面的命令,來檢測配置是否正確:sql
$ brew doctor
如有配置不當的地方,brew 會給出提示,安裝提示修復便可。shell
咱們將須要使用一些來自第三方倉庫的軟件,因此須要添加額外的倉庫:
$ brew tap homebrew/dupes $ brew tap homebrew/versions $ brew tap homebrew/php $ brew tap homebrew/apache
而後更新 brew:
$ brew update
接下來就能夠盡情使用 brew 了。
最新的 macOS 10.12 預裝了 Apache 2.4,但蘋果移除了一些必要的腳本,因此 Apache 和 Homebrew 配合使用將會變得困難。固然解決該問題的方法就是,使用 Homebrew 從新安裝配置 Apache,並使其運行在標準端口上(80/443)。
若是以前已經安裝有 Apache 而且在運行中,首先就須要關閉它,而後移除自動加載腳本。下面的命令沒有任何反作用,只管運行就行了:
$ sudo apachectl stop $ sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist 2>/dev/null $ brew install httpd24 --with-privileged-ports --with-http2
接下來須要等待一小會兒,由於這個命令是下載源碼並編譯安裝 Apache。上面命令執行結果以下面這樣:
? /usr/local/Cellar/httpd24/2.4.23_2: 212 files, 4.4M, built in 1 minute 45 seconds
這裏的路徑很重要,由於在接下來的步驟中,咱們都須要使用這個路徑,在這個例子中,路徑是 /usr/local/Cellar/httpd24/2.4.23_2/
,若是你的路徑不是這個,則在運行下面的命令的時候,將其替換爲你的路徑就能夠了:
sudo cp -v /usr/local/Cellar/httpd24/2.4.23_2/homebrew.mxcl.httpd24.plist /Library/LaunchDaemons sudo chown -v root:wheel /Library/LaunchDaemons/homebrew.mxcl.httpd24.plist sudo chmod -v 644 /Library/LaunchDaemons/homebrew.mxcl.httpd24.plist sudo launchctl load /Library/LaunchDaemons/homebrew.mxcl.httpd24.plist
如今咱們就經過 Homebrew 安裝上了 Apache,並使用管理員權限將其配置爲自動啓動。這個時候 Apache 應該已經在運行了,因此你打開瀏覽器訪問 localhost
將會看到 「It works!」。
若是你的瀏覽器提示說不能創建鏈接到服務器,那麼首先檢查一下 Apache 服務是否已經啓動了:
$ ps -aef | grep httpd
若是 Apache 正在運行,你將會看到一些 httpd 進程。
重啓 Apache:
$ sudo apachectl -k restart
咱們也能夠監控 Apache 的錯誤日誌,查看是否有錯誤信息:
$ tail -f /usr/local/var/log/apache2/error_log
若是上面這些步驟都沒有解決問題,那麼肯定你的 Apache 是否監聽了 80
端口,即 /usr/local/etc/apache2/2.4/httpd.conf
配置文件是否有 Listen: 80
,或者 Listen:
後面是其餘端口。
Apache 是經過 apachectl
來進行控制的,它的基本使用方法以下:
$ sudo apachectl start $ sudo apachectl stop $ sudo apachectl -k restart
-k
參數將強制重啓 Apache,無論 Apache 是否準備好。
最終我將個人 Apache 的端口修改成了 7070
,主要是由於 80
端口是 HTTP 服務的默認端口,8080
端口是 Tomcat 的默認端口,爲了不與其餘軟件如 nginx 等發生潛在端口衝突問題,因此改成了 7070
。
如今咱們已經有了一個 Web 服務器,接下來咱們須要對其進行一些配置,以便於更方便咱們本地的開發。
首先修改 Apache 的 document root
,這是 Web 服務的根目錄,Apache 會從這個目錄中尋找資源文件。默認的 document root 是 /Library/WebServer/Documents
。做爲一個開發環境,咱們可能更但願網站的根目錄(即 Web 服務的根目錄)在咱們本身的用戶主目錄下。因此接下來修改配置。
咱們能夠在終端經過 open -e
命令使用 Mac 默認的文本編輯器打開一個文件:
$ open -e /usr/local/etc/apache2/2.4/httpd.conf
搜索 DocumentRoot
,而後你會看到下面這行:
DocumentRoot "/usr/local/var/www/htdocs"
將這行配置改成本身的用戶主目錄中的目錄,把 your_user
改成你的用戶名:
DocumentRoot /Users/your_user/sites
緊接着還要將上面這行代碼下面的 <Directory>
也改成你的新的 document root:
<Directory /Users/your_user/sites>
在 <Directory>
代碼塊裏面,咱們還須要將 AllowOverride
改成下面的樣子:
# AllowOverride controls what directives may be placed in .htaccess files. # It can be "All", "None", or any combination of the keywords: # AllowOverride FileInfo AuthConfig Limit # AllowOverride All
接下來經過取消註釋使用 mod_rewrite
模塊:
LoadModule rewrite_module libexec/mod_rewrite.so
如今 Apache 已經指向了咱們的用戶主目錄下的 sites 目錄,不過依舊還存在一個問題。Apche 運行的時候,其用戶及用戶組都是 daemon
,當程序訪問咱們的用戶主目錄的時候,就會遇到權限問題。解決這個問題的方法就是,在 httpd.conf
將用戶和用戶組分別改成你的用戶名 your_user
和 staff
:
User your_user Group staff
接下來就須要在用戶主目錄下建立一個 sites
目錄了,而後添加一個簡單的 index.html
文件,並寫入 <h1>My User Web Root</h1>
代碼:
$ mkdir ~/Sites $ echo "<h1>My User Web Root</h1>" > ~/Sites/index.html
而後重啓 Apache 使配置生效:
$ sudo apachectl -k restart
再訪問 http://localhost
就會顯示 index.html
裏面的內容。若是你的配置也生效了,咱們就能夠繼續下一步了。
咱們接下來安裝 PHP 5.五、PHP 5.六、PHP 7.0 和 PHP 7.1,並使用一個簡單的腳原本切換不一樣的版本。
你可使用 brew options php55
來查看全部能夠安裝的選項設置,好比在這個例子中,咱們使用 --with-httpd24
參數來編譯安裝 PHP 以及使 Apache 支持 PHP 所須要的一些模塊。
$ brew install php55 --with-httpd24 $ brew unlink php55 $ brew install php56 --with-httpd24 $ brew unlink php56 $ brew install php70 --with-httpd24 $ brew unlink php70 $ brew install php71 --with-httpd24
上面的命令會從源碼下載 PHP,並進行編譯安裝。這可能須要一點時間。
若是以前已經安裝過 PHP,可能須要使用 reinstall
來代替 install
進行安裝。
我在安裝的時候遇到了一個錯誤:
==> ./configure --prefix=/usr/local/Cellar/php56/5.6.11_2 --localstatedir=/usr/local/var --sysconfdir=/usr/local/etc/php/5.6 --with-config-file-path=/usr/local/etc/php/5.6 --with checking whether to enable the SQLite3 extension... yes checking bundled sqlite3 library... yes checking for ZLIB support... yes checking if the location of ZLIB install directory is defined... no configure: error: Cannot find libz
最終在 Github 上找到了該 ISSUE [Cannot find libz when install php56 #1946
](https://github.com/Homebrew/h...。
其緣由多是 Xcode 的 Command Line Tool 沒有正確安裝。解決問題的方法是運行下面的命令來從新安裝:
xcode-select --install
可能你也須要根據本身的須要修改一些 PHP 的配置,常見的好比修改內存配置或 date.timezone
配置。各個版本的配置文件即 php.ini
在下面的目錄:
/usr/local/etc/php/5.5/php.ini /usr/local/etc/php/5.6/php.ini /usr/local/etc/php/7.0/php.ini /usr/local/etc/php/7.1/php.ini
咱們已經成功安裝了多個版本的 PHP,但咱們還須要告訴 Apache 怎麼使用它們。再次打開 /usr/local/etc/apache2/2.4/httpd.conf
,並搜索 #LoadModule php5_module
所在行。
能夠發現,每一個版本的 PHP 都有一個 LoadModule
入口,每一個 LoadModule
都指向一個特定版本的 PHP。這裏默認的路徑如 /usr/local/Cellar/php71/7.1.0_11/libexec/apache2/libphp7.so
是 brew
應用程序的安裝路徑,咱們可使用一個更通用的路徑來替換它們(具體的路徑可能有所不一樣):
LoadModule php5_module /usr/local/Cellar/php55/5.5.38_11/libexec/apache2/libphp5.so LoadModule php5_module /usr/local/Cellar/php56/5.6.29_5/libexec/apache2/libphp5.so LoadModule php7_module /usr/local/Cellar/php70/7.0.14_7/libexec/apache2/libphp7.so LoadModule php7_module /usr/local/Cellar/php71/7.1.0_11/libexec/apache2/libphp7.so
將上面的路徑修改成:
LoadModule php5_module /usr/local/opt/php55/libexec/apache2/libphp5.so LoadModule php5_module /usr/local/opt/php56/libexec/apache2/libphp5.so LoadModule php7_module /usr/local/opt/php70/libexec/apache2/libphp7.so LoadModule php7_module /usr/local/opt/php71/libexec/apache2/libphp7.so
之因此能夠這麼修改,是由於 /usr/local/opt/php71
實際上是由 brew
建立的 /usr/local/Cellar/php71
的一個軟鏈接。
這麼修改的好處是,升級 PHP 的小版本號的時候,好比由 7.1.0_11
時,咱們就不須要再修改 LoadModule
對應的值了。
咱們每次開發或運行依舊只須要通常也只能使用某一個版本的 PHP。以咱們要使用 7.1 這個版本開發應用爲例,將其餘版本的 LoadModule
都註釋掉,只保留對應版本的 LoadModule
:
#LoadModule php5_module /usr/local/opt/php55/libexec/apache2/libphp5.so #LoadModule php5_module /usr/local/opt/php56/libexec/apache2/libphp5.so #LoadModule php7_module /usr/local/opt/php70/libexec/apache2/libphp7.so LoadModule php7_module /usr/local/opt/php71/libexec/apache2/libphp7.so
這樣的配置就會告訴 Apache 使用 PHP 7.1 來處理 PHP 請求。(稍後咱們將添加切換 PHP 版本的腳本。)
接下來還須要配置 PHP 的主目錄索引文件(Directory Indexes),找到下面的代碼塊:
<IfModule dir_module> DirectoryIndex index.html </IfModule>
將其替換爲下面的代碼:
<IfModule dir_module> DirectoryIndex index.php index.html </IfModule> <FilesMatch \.php$> SetHandler application/x-httpd-php </FilesMatch>
保存後重啓 Apache,PHP 的安裝就完成了:
$ sudo apachectl -k restart
驗證 PHP 是否正確安裝的最好方法是使用 phpinfo()
這個函數,這個函數會輸出 PHP 的版本等信息。固然,最好不要在你的生產環境中使用它。但在開發環境中,使用它對咱們瞭解系統中 PHP 安裝信息很是有幫助。
在網站主目錄即你的 sites/
目錄下建立一個 info.php
的文件,而後輸入下面的代碼:
<?php phpinfo(); ?>
打開瀏覽器,訪問 http://localhost:7070/info.php
,你講看到下面的完美的 PHP 信息頁面:
若是可以看到相似的頁面,就說明 Apache 和 PHP 已經成功運行了。你能夠經過註釋 LoadModule ... php56 ...
來測試其餘版本的 PHP。修改配置後,重啓 Apache 並刷新頁面就能看到相似的頁面了。
在開發中,若是每次都經過修改 /usr/local/etc/apache2/2.4/httpd.conf
文件去切換 PHP 版本,顯然太麻煩了。有沒有更容易的方法呢?幸運的是,一些勤勞的開發者已經寫好了這樣的一個腳本 PHP switcher script。
接下來咱們將添加 sphp
到 brew 的 /usr/local/bin
裏面。原文給的方法是使用下面的命令:
$ curl -L https://gist.github.com/w00fz/142b6b19750ea6979137b963df959d11/raw > /usr/local/bin/sphp $ chmod +x /usr/local/bin/sphp
其中第一行命令的做用,就是將 Gist 上的這個切換 PHP 版本的腳本下載並寫入到 /usr/local/bin/sphp
這個文件裏面。第二行命令的做用是賦予 /usr/local/bin/sphp
可執行權限。
但因爲國內並不能訪問 Gist,因此第一行命令並不能執行成功。因此我在這裏提供了整個腳本代碼:
#!/bin/bash # Check if command was ran as root. if [[ $(id -u) -eq 0 ]]; then echo "The command \"sphp\" should not be executed as root or via sudo directly." echo "When a service requires root access, you will be prompted for a password as needed." exit 1 fi # Usage if [ $# -ne 1 ]; then echo "Usage: sphp [phpversion]" echo "Versions installed:" brew list | grep '^php[0-9]\{2,\}$' | grep -o -E '[0-9]+' | while read -r line ; do echo " - phpversion: $line" done exit 1 fi currentversion="`php -r \"error_reporting(0); echo str_replace('.', '', substr(phpversion(), 0, 3));\"`" newversion="$1" majorOld=${currentversion:0:1} majorNew=${newversion:0:1} minorNew=${newversion:1:1} brew list php$newversion 2> /dev/null > /dev/null if [ $? -eq 0 ]; then echo "PHP version $newversion found" # Check if new version is already the current version. # if [ "${newversion}" == "${currentversion}" ]; then # echo -n "PHP version ${newversion} is already being used. Continue by reloading? (y/n) " # while true; do # read -n 1 yn # case $yn in # [Yy]* ) echo && break;; # [Nn]* ) echo && exit 1;; # esac # done # fi echo "Unlinking old binaries..." brew unlink php$currentversion 2> /dev/null > /dev/null echo "Linking new binaries..." brew link php$newversion echo "Linking new modphp addon..." sudo ln -sf `brew list php$newversion | grep libphp` /usr/local/lib/libphp${majorNew}.so echo /usr/local/lib/libphp${majorNew}.so echo "Fixing LoadModule..." apacheConf=`httpd -V | grep -i server_config_file | cut -d '"' -f 2` sudo sed -i -e "/LoadModule php${majorOld}_module/s/^#*/#/" $apacheConf if grep "LoadModule php${majorNew}_module .*php${newversion}" $apacheConf > /dev/null then sudo sed -i -e "/LoadModule php${majorNew}_module .*php${newversion}/s/^#//" $apacheConf else sudo sed -i -e "/LoadModule php${majorNew}_module/s/^#//" $apacheConf fi echo "Updating version file..." pgrep -f /usr/sbin/httpd 2> /dev/null > /dev/null if [ $? -eq 0 ]; then echo "Restarting system Apache..." sudo pkill -9 -f /usr/sbin/httpd sudo /usr/sbin/apachectl -k restart > /dev/null 2>&1 fi pgrep -f /usr/local/"Cellar|opt"/*/httpd 2> /dev/null > /dev/null if [ $? -eq 0 ]; then echo "Restarting homebrew Apache..." sudo pkill -9 -f /usr/local/"Cellar|opt"/*/httpd sudo /usr/local/bin/apachectl -k restart > /dev/null 2>&1 fi # pgrep -x httpd 2> /dev/null > /dev/null # if [ $? -eq 0 ]; then # echo "Restarting non-root homebrew Apache..." # httpd -k restart > /dev/null 2>&1 # fi echo "Done." # Show PHP CLI version for verification. echo && php -v else echo "PHP version $majorNew.$minorNew was not found." echo "Try \`brew install php${newversion}\` first." exit 1 fi
經過 open -e /usr/local/bin/sphp
打開 sphp
文件,並將上面的代碼複製進入,而後賦予可執行權限:
$ chmod +x /usr/local/bin/sphp
Homebrew 在安裝程序的時候通常會把程序的可執行文件加入到 /usr/local/bin
和 /usr/local/sbin
這兩個目錄裏面。經過下面的命令能夠快速測試可執行文件路徑是否正確:
$ echo $PATH /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
若是沒有看到相似的輸出,你可能須要手動添加這些路徑。添加下面的代碼到 shell 的配置文件中(不一樣的 shell 可能須要將路徑添加到不一樣的配置文件中,如 ~/.profile
~/.bash_profile
~/.zshrc
)。若是使用的是 macOS 默認的 shell,則添加到 ~/.profile
(若沒有這個文件,則建立它);若是使用的是 zsh,則添加到 ~/.zshrc
:
export PATH=/usr/local/bin:/usr/local/sbin:$PATH
在添加路徑到配置文件的時候,最好關閉其餘不相關的終端,由於某些開着的終端可能會對路徑形成一些奇怪的問題。添加完成後,配置會在下次打開終端的時候生效。或者使用下面的命令,從新載入配置文件使其當即生效:
# 若使用的是默認終端 $ source ~/.profile # 或若是使用的是 zsh $ source ~/.zshrc
儘管以前咱們已經配置好了 Apache 和 PHP,如今咱們還須要修改配置文件,來使用 PHP switcher script
切換 PHP 的版本。繼續打開 /usr/local/etc/apache2/2.4/httpd.conf
而後找到 LoadModule php
所在的行:
而後註釋掉正在使用的 LoadModule
:
#LoadModule php5_module /usr/local/opt/php55/libexec/apache2/libphp5.so #LoadModule php5_module /usr/local/opt/php56/libexec/apache2/libphp5.so #LoadModule php7_module /usr/local/opt/php70/libexec/apache2/libphp7.so #LoadModule php7_module /usr/local/opt/php71/libexec/apache2/libphp7.so
並在下面添加:
# Brew PHP LoadModule for `sphp` switcher #LoadModule php5_module /usr/local/lib/libphp5.so LoadModule php7_module /usr/local/lib/libphp7.so
若是你安裝了 PHP 5.5 或 5.6 等,註釋掉的 php5_module
一樣也很是重要。PHP switcher script
會自動註釋或取消註釋 PHP module。
完成上面的步驟以後,就可使用 sphp
命令來切換 PHP 版本了。sphp
的參數是由兩個數字組合成的兩位數:
$ sphp 5 PHP version 55 found Unlinking old binaries... Linking new binaries... Linking /usr/local/Cellar/php55/5.5.38_11... 17 symlinks created Linking new modphp addon... /usr/local/lib/libphp5.so Fixing LoadModule... Updating version file... Restarting homebrew Apache... Done. PHP 5.5.38 (cli) (built: Dec 28 2016 15:48:28) Copyright (c) 1997-2015 The PHP Group Zend Engine v2.5.0, Copyright (c) 1998-2015 Zend Technologies
而後訪問 http://localhost:7070/info.php
,能夠看到 PHP 版本已經正確切換:
我在切換版本的時候也遇到了問題:
$ sphp 71 ... Warning: PHP Startup: Unable to load dynamic library '/usr/local/opt/php56-mongo/mongo.so' - dlopen(/usr/local/opt/php56-mongo/mongo.so, 9): image not found in Unknown on line 0 PHP 5.6.29 (cli) (built: Dec 28 2016 15:58:30) Copyright (c) 1997-2016 The PHP Group Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
根據錯誤提示,大概是由於 php56-mongo
這個擴展沒有,因而我使用 brew 安裝了 php56-mongo
問題就解決了:
$ brew install php56-mongo
使用 brew 更新 PHP 和其餘經過 brew 安裝的程序很是簡單,第一步是更新 brew 自己:
$ brew update
升級後將會列出一系列可測迴歸心裏的程序,而後使用下面的命令更新:
$ brew upgrade
當咱們使用 PHP 的時候,每次咱們只使用了其中一個版本,而且只有當前使用的版本會更新到最新版本。可使用下面的命令查看當前 PHP 版本:
$ php -v
可使用下面的命令查看具體的可用 PHP 版本:
$ brew info php55 homebrew/php/php55: stable 5.5.38 (bottled), HEAD PHP Version 5.5 https://php.net Conflicts with: php53, php54, php56, php70, php71 /usr/local/Cellar/php55/5.5.38_11 (329 files, 47.7M) Built from source on 2016-12-28 at 15:49:20 with: --with-httpd24
好比上面的 PHP 5.5 版本的只有一個可用版本 5.5.38。
而後可使用 brew 來切換到一個具體的版本:
$ brew switch php55 5.5.38
到此,這篇文章就結束了。你已經完成掌握了 Apache 2.4 和各個版本 PHP 的安裝,而且可以在 5.5 5.6 7.0 7.1 中快速切換 PHP 版本。原做者還寫了兩外兩篇文章,分別是 macOS 10.12 Sierra Apache Setup: MySQL, APC & More 和 macOS 10.12 Sierra Apache Setup: SSL,近期內我也會將它們翻譯成中文,並加入本身的實踐總結。