Category: PHP

  • 輸入一正數用星號印出正三角形

    輸入一正數用星號印出正三角形

    印象中是在 PTT 上看到這題目…想說自己寫 code 多年,好像沒寫過這題。覺得有趣就用 PHP 試著實作看看。 先看結果… 程式如下: 因為公司的螢幕沒特別大,最多只能顯示 43 行…. 這種小測試寫起來蠻有趣的

  • CentOS 7 安裝、升級 PHP 5.6

    轉眼間當年幫客戶架設的 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…

  • Best practice to generate random token in PHP

    在 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?

    How to Flatten a Multidimensional Array in PHP?

    最近碰到的小需求:如何將多維陣列攤平成一維陣列?…. 本來以為 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)。

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

    公司跟一家新廠商展開合作,其中交換電文是用 CSV 格式。但對方要求所有的欄位都要用 ” 雙引號包起來。看起來就像下圖這樣。 但是很不巧的,PHP 內建產生 CSV 的指令 fputcsv 沒有提供強制的選項。做出來的檔案如下圖。 山不轉只好路轉… 在丟進 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 字元預設就是雙引號,無法替換成空白,只好用…

  • Connection could not be established with host

    最近重灌了工作用的筆電,把開發環境的 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 套件為例,它的…

  • How to get length of integers in PHP?

    在寫 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 override the path of PHP to use the MAMP path?

    最近在學習 Laravel Framework 的使用,現在 PHP 許多 Library、Framework 都改用了 composer.phar 這個套件管理功能。 其中許多管理功能需要在 command line 輸入指令,但是 Mac 其實也有內建 PHP,卻缺了許多常用的套件。 與其去補安裝套件,不如改用 MAMP 的 PHP 還比較省事。 在 ~/.bash_profile 加入以下指令: export PATH=”/Applications/MAMP/bin/php/php5.5.3/bin:$PATH” 這樣使用 PHP 指令就會自動選用 MAMP 下的版本和套件,其中紅字請改為您使用的版號。

  • PHPExcel: Delete sheets

    PHPExcel: Delete sheets

    PHPExcel 是 PHP 所有第三方套件裡,功能相當強大的一款,主要用途是用來讀寫 Excel (.xls)、Excel 2007 (.xlsx)、Libre/OpenOffice Calc (.ods)、CSV 等等各種試算表文件。 儘管是個強大的套件,個人倒是覺得這套件的語法相當複雜、不夠直覺,文件也不是非常容易閱讀,往往還是去找 stack overflow 的範例更快。 最近在幫客戶開發報表的功能,匯出 Excel 試算表是常見的作法。寫著寫著,突然想到每次產生只有一個 sheet 的試算表,都會被自動再加一張空白的 sheet … 就像下圖這般。 然後就…. 很想刪掉它 XD 在 stackoverflow 沒看到討論,倒是官方論壇有討論到,用法難得的直覺 (?)。 $objPHPExcel->removeSheetByIndex(1); 參數是第幾個 sheet,從 0 開始,所以要刪除 [Worksheet 1],就代入參數 1 醬。

  • Detect Browser Language in PHP

    Detect Browser Language in PHP

    最近某個已經上線的專案新增了製作多國語系介面的需求,流程上打算用 PHP 來偵測使用者瀏覽器的語言設定。

  • Force SSL/https using mod_rewrite or PHP

    工作需求,要幫某網站全部轉為 HTTPS 加密傳輸。 有兩種方法,一是透過 .htaccess,二是用 PHP 來處理。 用 .htaccess 處理的方式如下 RewriteEngine On RewriteCond %{HTTPS} !=on RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] 用 PHP 來處理: if (!isset($_SERVER[‘HTTPS’]) || $_SERVER[‘HTTPS’] !== ‘on’) { if(!headers_sent()) { header(“Status: 301 Moved Permanently”); header(sprintf( ‘Location: https://%s%s’, $_SERVER[‘HTTP_HOST’], $_SERVER[‘REQUEST_URI’] )); exit(); } } 個人比較偏好用 .htaccess 來處理。不過若是沒有全部頁面都需要的話,PHP 比較方便。  

  • Check if PHP session has already started

    用 PHP 寫系統基本上躲不掉 session 相關的一系列問題的。因為個人偏好 CodeIgniter,所以很多時候用 Session Library 或是開源的 Native Session Library 就可以避開一些煩瑣的麻煩。 不過很多時候碰到沒有使用 framework 當基礎,直接用 PHP 開發的專案時,程式碼裡 “充斥” 著 session_start() 也是非常普遍的事情,接著就會一直在 error_log 裡看到這樣的訊息: PHP Notice:  A session had already been started 看了有夠礙眼,也讓人覺得很不專業。 其實這問題是可以避免的。只要在宣告前檢查是否啟動就好。 isset($_SESSION) or session_start(); 如果使用的是 PHP 5.4 以上的版面,還有更可靠的寫法。 (session_status() !== PHP_SESSION_ACTIVE) or session_start(); 乾乾淨淨的是 error_log 才是開發者的王道。

  • Disable Cache for PHP 5.5.3 in MAMP

    前些時間接手一個已經上線的案子,進行改版作業。從 Git 上把 code 拉下來,執行一下就… 爆了。發現同事用了相當新的 PHP 語法。我本機的開發環境是 PHP 5.2.x,無法執行。 馬上想到 MAMP 可以切換成新的版本,切換成 5.5.3 問題就解決了。

  • Codeigniter: Check if libraries/helper/core files is loaded

    使用 CodeIgniter 框架開發時,會透過 $this->load->library() 之類的方法來載入特定的檔案。在 CI 的 routing 規則中,同一個檔案只會被載入一次,因此多寫幾次 $this->load->library() 是不會發生什麼慘劇的。 不過有時候還是想確認到底某 class 有沒有載入過,而不想到處丟 $this->load->xxx() 的話,可以用以下方法來確認。 if (class_exists(‘Library’)) { $this->library->myMethod(); } 要注意的是 CI 有別名的規則,比如說有個 model 叫 ‘file_model’。使用別名載入時,會寫成以下 $this->load->model(‘file_model’, ‘file’); $this->file->do_something(); 這種情況下,若要檢查是否已載入,要用原名。如下: if (class_exists(‘File_model’)) { // do something }

  • Installing ionCube Loader on MAMP

    在幫客戶 debug 的時候注意到 SVN 裡一小部份程式碼居然被 ionCube 加密過了…. 加密後的程式碼丟到 SVN 是有個屁用啊。 算了,這不重要。重點是我的開發機變成也要可以執行 ionCube 才行。要在 Mac 上的 MAMP 下安裝 ionCube loader 還蠻簡單的,隨手筆記一下。ionCube 的 loader 是免費的,encoder 才要付費。 先到 Loaders for ionCube Encoded Files 下載對應的 loader。我的開發環境是 OS X (x86-64)。下載了 .zip 包,解開來有幾個檔案。 其中的數字是 PHP 的版本,例如 5.2, 5.3 等,_ts 是指 Thread Safety,MAMP 的 PHP 沒有 Thread Safety,所以選用一般版即可。如果不確定環境有沒有 ts,可以用 phpinfo 看一下。 建議將…

  • Formula Error in PHPExcel

    最近在幫客戶開發報表功能,其中一個小功能是將查詢結果匯出成 Excel 檔案,對於會計人員來說相當依賴 Excel。 如果沒有什麼特別的需求,通常會用 PHPExcel 來製作檔案。 一個典型的儲存格設定如下: $objPHPExcel->setActiveSheetIndex(0) ->setCellValue(‘B6’, $order[‘order_no’]); 就在這個匯出功能即將完成時,發現有一個欄位只要一存入內容,PHPExcel 就會出現 Formula Error。 回頭去看資料庫,發現是 VCHAR 欄位,那寫入應該沒啥問題啊。再看看資料內容… 看了兩眼才注意到這個純文字欄位有幾格是 = (等號) 開頭… bingo! PHPExcel 在指值的時候,碰到等號會轉換成公式,自然就爆掉了。解決方法是把 setCellValue() 換成 setCellValueExplicit(),這樣就不會被轉換了。 收工!

  • PHP FIG Group PSR standard 程式風格

    這兩天在查資料的時候才知道有 PSR 風格。這是由 PHP FIG Group 所訂的規範。FIG 這個組織是由一群開發 Open Source PHP 專案的開發者所組成,目的在於以最低程度的限制來統一各個專案的 coding style,避免各家自行發展的風格阻礙了程式設計師撰寫的困擾。 PSR 規範有四套,分別為 PSR-0 (Autoloading standard) PSR-1 (Basic Coding Standard) PSR-2 (Coding Style Guide) PSR-3 (Logger Interface) 依順序有繼承性,每一篇都很簡短,蠻建議看看。

  • PHP: Finding the year quarter for a date

    在工商業應用中,時間紀錄是系統中非常基本的東西,不過時間的表示方法就五花八門了。最近碰到一個需求是同一個時間欄位可能是 Y-m-d (ex. 2012-11-29)、quarter (Q4 2012)、month (Nov 2012),或是 year (2012),甚至是 TBA (to be announced)。 其中轉換成季 (quarter) 會用到一點點技巧,在此筆記如下: <? $timestamp = mktime(0, 0, 0, 11, 29, 2012); echo ceil(date(“m”, $timestamp)/3); ?> 只要前面再加個 ‘Q’ 就是第幾季了。 在資料庫部份如何分辨客戶是儲存哪種型態,我的做法是多開一個 date_type 的欄位。 CREATE TABLE `calendar` ( `c_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `c_date` date NOT NULL, `c_date_type` char(1) NOT NULL DEFAULT…

  • Sharpen an image using PHP and GD

    同事正在開發一個購物平台,店家可以上傳商品照片,由系統自動縮圖到適合版面的大小,不過 resize 後圖片品質明顯下降,於是同事問我有沒有解法。同事問我並不是因為我比較強,只是因為我的位子在他旁邊。 跟同事討論了一下,試用了 imagecopyresized 和 imagecopyresampled 兩個函式來縮圖,前者的細節比較好,但部份線條出現明顯的變形,後者圖形正確,但看起來比較模糊。所以先用後者縮圖,再想辦法銳化圖片。 印象中 PHP GD Library 並沒有直接提供 sharpen (銳化) 相關的函式,但是 Google 一下,發現有 imageconvolution 濾鏡可以用,真是有趣,沒想到可以自訂濾鏡,以前在學校修過影像處理課程的回憶…. 都忘光光了。還好不難找到幾組範例。 <?php // create the image resource from a file $i = imagecreatefromjpeg(‘otter.jpg’); // define the sharpen matrix $sharpen = array( array(0.0, -1.0, 0.0), array(-1.0, 5.0, -1.0), array(0.0, -1.0, 0.0) ); // calculate the sharpen…

  • Regular expression which matches a pattern, or is an empty string

    之前介紹過在 jQuery Validation Plugin 使用正規表達式 (Regular Expression) 的方法。 在某個專案中如常地用這個方法做表單欄位檢查,不過客戶提了一個需求,希望該欄位不是必填,但使用者有填資料時要驗證其內容。 原本的驗證條件是這樣的… regex : “[0-9]{4}-[0-9]{6}” 也就是使用者一定要輸入正確的手機號碼,如 0919-123456。要變成選填的話… 想了一下,改成下面這樣就可以了。 regex : “([0-9]{4}-[0-9]{6})?” 前後加上括號,然後用最未端的 問號 來表示 前面這串括號裡的文字可以不出現或出現一次。