Category: Programming

Laravel 4.x WhoopsDisplayer::display() must be an instance of Exception

Posted by – September 28, 2017

有個用 Laravel 4.2 開發的舊專案,近來經常遇到下面這個錯誤

PHP Fatal error: Uncaught TypeError: 
Argument 1 passed to Illuminate\Exception\WhoopsDisplayer::display() 
must be an instance of Exception, instance of ParseError given

找了許多討論都提到是 Laravel 4.x 與 PHP 7 不相容的關係。但我的開發環境有 PHP 5.6 和 PHP 7,似乎前者也有機會發生,十分不解。

每當發生這個 Error 就不會看到真正的 Exception 訊息,debug 十分困擾。

Stackoverflow 上找到一個應急用的解法,可以用在開發環境上....

app/config/local/app.php 的檔案開頭加兩行

set_error_handler(null);
set_exception_handler(null);

暫時搞定了...

CentOS 7 安裝、升級 PHP 5.6

Posted by – September 16, 2017

轉眼間當年幫客戶架設的 server 也好幾年了。隨著程式碼的迭代,server 也到了不得不更新的時候了。不過目標沒有很遠,只要把 PHP 5.4 升到 5.6 就可以了。

把升級的過程筆記一下

首先是更新 EPEL 庫

yum install epel-release

rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

接著更新 Remi 庫

rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm

檢查系統安裝了哪些和 PHP 相關的套件

rpm -qa | grep php

要升級的話要先移除舊套件。因為 PHP 版更,相關的 extension 都要換成相對應的版本才行。注意以下指令可能也會把 phpmyadmin 一起移除

yum remove php-*

啟用 Remi 庫,用編輯器打開以下檔案

/etc/yum.repos.d/remi.repo

找到這一段... 把 enabled 設為 1

[remi-php56]
name=Les RPM de remi de PHP 5.6 pour Enterprise Linux 6 - $basearch
#baseurl=http://rpms.famillecollet.com/enterprise/6/php56/$basearch/
mirrorlist=http://rpms.famillecollet.com/enterprise/6/php56/mirror
# WARNING: If you enable this repository, you must also enable "remi"
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-remi

接著安裝 PHP 套件們

yum install --enablerepo=remi,remi-php70 php php-devel php-mbstring php-pdo php-gd php-xml php-mcrypt php-mysql

安裝完成後重啟 httpd service 即可

要注意的是 php.ini 會被洗掉哦

Best practice to generate random token in PHP

Posted by – January 10, 2017

在 Stackoverflow 看到一篇超級實用的文:在 PHP 中產生隨機字串的最佳實踐。

產生隨機字串這個看似不起眼的議題實作起來還挺麻煩的,曾經為了如何產生字串跟同事討論了許久。

$length = 16;
$token = bin2hex(openssl_random_pseudo_bytes($length));
# => e9bf18672b051619a3479ecbe1cb7d08

唯一的參數 $length 可以替換成任意整數,產生的字串長度就是 $length *2。

同場加映,Google Chrome 的亂數演算法也有改過

How to Flatten a Multidimensional Array in PHP?

Posted by – January 9, 2017

最近碰到的小需求:如何將多維陣列攤平成一維陣列?....

本來以為 PHP 那巨大的 Lib 會有一個神奇的 function 完成這任務,結果翻了一遍 php.net 的文件,沒有找到這神奇的功能。不過還是有另一個神妙的 function 可以拿來用,那就是 array_walk_recursive,這個 function 會有遞迴的方式走完整個 array,然後看使用者後續想幹嘛...

以攤平一維陣列為例,以下是只保留 value 的作法...

function flatten(array $array) {
  $return = array();
  array_walk_recursive($array, function($a) use (&$return) {
    $return[] = $a; 
  });
  return $return;
}

如此一來就可以將多維陣列轉為一維。若是要保留 key 與 value,要注意 key 名稱是否有重複 (isset)。

將 Sequel Pro 的表導出成 Laravel migration 文件

Posted by – December 23, 2016

Laravel 學院看到一篇有趣的文,筆記下。


将 Sequel Pro 中已存在的数据表导出为 Laravel 迁移文件

對於用 Mac 的開發者來說頗為實用。Sequel Pro 這款 MySQL GUI 也是我用過最好用、最順手的 DB 管理工具,沒有之一,輕巧高效,可惜支援的 DB 種類不多。

強制 fputcsv 所有欄位都加上雙引號

Posted by – August 2, 2016

公司跟一家新廠商展開合作,其中交換電文是用 CSV 格式。但對方要求所有的欄位都要用 " 雙引號包起來。看起來就像下圖這樣。

Screen Shot 2016-08-02 at 2.58.00 PM

但是很不巧的,PHP 內建產生 CSV 的指令 fputcsv 沒有提供強制的選項。做出來的檔案如下圖。

Screen Shot 2016-08-02 at 3.03.33 PM山不轉只好路轉...

在丟進 fputcsv 前就先用雙引號包一包。

<?php

function forceQuote($value) {
    return "\"$value\"";
}

$file = @fopen($file_path, "w");

foreach ($data['content'] as $line) {
    fputcsv(
        $file,                          // 輸出檔名
        array_map('forceQuote', $line), // 先包雙引號
        ',',                            // 資料用逗號分隔
        chr(0)                          // 跳脫預設的 enclosure 字元
    );
}

fclose($file);

比較特別是 fputcsv 原本的 enclosure 字元預設就是雙引號,無法替換成空白,只好用 chr(0) 來跳脫,不然每一筆資料會變成 """aaa""",三個引號…

這樣就可以交差了。

Connection could not be established with host

Posted by – July 19, 2016

最近重灌了工作用的筆電,把開發環境的 PHP 升級到 5.6.10,然後就各種狀況.....

其中一個問題是從本機連不上公司 mail server,所以寄信功能就掛掉了。Laravel log 的訊息如下

local.ERROR: 500 - Connection could not be established with host xxx.com.tw [ #0] @ /
exception 'Swift_TransportException' with message 'Connection could not be established with host xxx.com.tw [ #0]' in laravel/vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php:270

原來是因為從 PHP 5.6 開始,變更了 SSL 認證的預設值,verify_peer 與 verify_peer_name 這兩項安全檢查都被改為預設,然後很多 SSL verification 就過不了。雖然提高安全性是好事,但開發環境卻造成一些困擾。

以上述的 swiftmailer 套件為例,它的 SSL 連線是用 stream_socket_client 實現的,其參數設置是透過 stream_context_create 傳入,所以設定方式如下:

$contextOptions = [
    'ssl' => [
        'verify_peer' => false,
        'verify_peer_name' => false
    ]
];
$context = stream_context_create($contextOptions);
stream_socket_client(
    $host.':'.$port, 
    $errno, 
    $errstr, 
    $timeout, 
    STREAM_CLIENT_CONNECT, 
    $context
);

如此一來就可以關閉檢查,終於可以連上 mail server 了。收工。

How to get length of integers in PHP?

Posted by – May 25, 2016

在寫 code 的時候想到這個無關緊要的問題... 如何得知一個數字有幾位數?

比較直覺的想法是這樣....

function digits($num) {
    return (int) strlen((string) abs($num));
}

在 stackoverflow 看到一個也不賴的寫法....

function digits($num) {
    return (int) log(abs($num), 10) + 1;
}

筆記一下,都快忘了 log 怎麼算 XD

How to disable phone number linking in Mobile Safari?

Posted by – November 4, 2015

同事問了這個問題,如何將 iOS webview 裡出現的電話連結移除,因為畫面中出現了不是電話的數字,卻被系統自動加上了電話連結。

有一個非常簡單的方法,在 HTML 檔案的 <head> 區段加一行宣告即可。

<meta name = "format-detection" content = "telephone=no">

這行宣告會停用所有的電話連結。若是反過想要在停用的情況下,加上例外,則可以自行宣告電話連結,語法如下:

<a href="tel:0932123456">0932123456</a>

主要就是用 tel: 關鍵字來達成。

Laravel 5.0: 紀錄 SQL 指令

Posted by – August 22, 2015

在同事轉貼的一些文章裡翻到這篇记录运行时SQL语句,稍微修改一下,在我的 Laravel 5.0 測試站上實作。

文章中的第一步我就傻眼了,因為我的 php artisan list 裡面沒有 make:listener.... More