如果引用或轉貼,麻煩註明出處與本網誌連結,否則視為侵權。
顯示具有 PHP 標籤的文章。 顯示所有文章
顯示具有 PHP 標籤的文章。 顯示所有文章

2023年1月17日

Codeigniter系統異常登出問題 "Session Error" 原因與解決方法

作者: Fred F.M. Wang (FW知識瑣記) 日期: 2023-1-17

最近開發PHP+Codeigniter架構的網站發生奇怪的問題 :

程式碼 : 
$this->session->set_userdata("message",$msg);
redirect($prev_page);
上述程式碼執行要redirect(重導)到另一個網頁,卻發生登入者自動被登出。

經過一番測試,終於發現問題在哪裡了。

我系統的設計是 : 
1. 用Session儲存使用者登入的資訊,系統各個頁面會根據此登入資訊判斷是否處於登入狀態。  $this->session->set_userdata("username",$username);
   ***** 顯然上面的問題是Session中使用者登入資訊已經消失了。*****
2.  用Session儲存訊息,如上面的$this->session->;set_userdata("message",$msg); 重導到另一個網頁時,再讀出此資料顯示在頁面上,如$message = $this->session->userdata("message");。

原因一 : 與預設編碼不同。
$this->session->set_userdata("message",$msg); 這行程式的$msg變數中包含Big5中文編碼的文字,
而Codeigniter系統設定application/config/config.php中預設編碼為UTF-8
$config['charset'] = "UTF-8"; 
內容與預設編碼不同,造成Session資料的消失。

解決方法 :,只要將上面$msg轉換為UTF-8編碼格式就不會有問題了。


原因二 : 也有可能是設定的內容太長 
解決方法 : 縮短訊息內容長度就不會發生了。(或加大session容量,需要其他設定)


參考 :  網路上其他類似的問題與Session data lost可能的原因

2022年12月1日

PHP常用的日期時間格式整理

作者: Fred F.M. Wang (FW知識瑣記) 日期: 2022-12-1

以下為筆者整理常用的PHP擷取日期時間的格式。

PHP語法 : 

$data = date("<格式>", strtotime($date_string))


格式 : 

日(每月幾號,當月的第幾天)

d : 01~31

j  : 1~31

S : 每月第幾個日期, 與j可共用 st, nd, rd, th…

     ex: jS : 1st, 2nd, 3rd, 4th….


星期幾

w : 0~6 (0 for Sunday)

N : 1~7 (7 for Sunday) 

D : Mon~Sun

l (小寫L) : Sunday~Saturday


一年的第幾天 

z : 0~365 (0: 第一天)


一年的第幾周

W : 從該年第一個星期一算起 


月份

m : 01~12

n : 1~12

M : Jan~Dec

F : January~December


該月份共幾天(最後一天的日期) *****

 t : 28~31, date(“Y-m-t”) 本月最後一天 


年 

Y : ex. 1999

y : ex. 99


是否為閏年 

L : 1閏年 0非閏年


時

H : 24小時制00~23

G : 24小時制0~23

h : 12小時制01~12

g : 12小時制1~12

A:  AM or PM

a : am or pm


分

 i : 00~59


秒 

s : 00~59


毫秒 

v: ex:645



2022年11月1日

Codeigniter Word套表應用的開發步驟

作者: Fred F.M. Wang (FW知識瑣記) 日期:2022-11-1

    PHP的Excel的套表應用開發程序比較單純,直接可以用程式將資料寫入樣板檔的相關儲存格,但是Word的套表就必較複雜,如下圖右邊為Excel套表的開發步驟,左邊是Word套表的開發步驟。
 



準備 :
Codeigniter使用PHPWord版本是CI_PHPWord,程式庫來源為https://github.com/rifqisucahyo/CI_PHPWord
依連結中的說明,將各檔案放到您 Codeigniter專案的資料夾中。
然後將phpword\template.php檔案的這行註釋掉:$replace = utf8_encode($replace);


樣板製作與程式設計步驟 :

Step 1 將設計好的Word表單檔(.docx檔)使用MS Word轉存成XML檔。


Step 2 使用文字編輯器編輯XML, 找到檔案中放資料位置,插入變數,格式為 ${變數名稱}


Step 3 再將編輯完成的XML檔使用MS Word轉存成Word表單檔(.docx檔),再將這個帶有變數名稱的樣板檔放在Server上成為正式的樣板。


Step 4 撰寫程式,將資料寫入樣板文件的變數中,並儲存成表單文件檔。


注意 : 

1. 如果要變更樣板內容,不能直接編輯Step 3的樣板檔(.docx檔),必須修改Step 1產生的XML檔,再進行Step 2至Step 4。

2. 內容中如果有&符號會造成轉換後的Word檔無法讀取,因此先將內容的”&”用逗號等符號取代,再寫入。例如 $objPHPWordOut->setValue("desc",str_replace("&",",",$data["description"]));  


範例程式 : 

 
// 樣本檔檔案路徑為$templatefile, 例如下面程式
$templatefile = dirname($_SERVER["SCRIPT_FILENAME"]) . "/templates/app1/form_template.docx";

// 要寫出的檔案路徑為$outfilepath, , 例如下面程式
$outfile = "exports/app1/doc_" . date("YmdHis"). ".docx";    
$outfilepath = dirname($_SERVER["SCRIPT_FILENAME"]) . "/" .$outfile;    

$this->load->library("word");
$PHPWord = $this->word;            
$objPHPWordOut = $PHPWord->loadTemplate($templatefile);   // 載入樣板檔
// $data是要寫入的資料陣列
$this->write_data_to_word($objPHPWordOut,$data);   // 寫入資料
$objPHPWordOut->save($outfilepath);    // 儲存至寫出檔案

private function write_data_to_word($objPHPWordOut,$data) {            
       // 將$data[“id”]的內容取代樣板檔中變數id也就是 $id
       $objPHPWordOut->setValue("id",$data["id"]);
       …
}

參考來源 : PHPWord中文手冊整理- ITW01

 

2021年9月2日

如何解決PHP日期2038年的限制?

作者: Fred F.M. Wang (FW知識瑣記) 日期:2021-9-2

以往以PHP寫日期相關程式,習慣用strtotime函式將字串轉換為時間,並用date函式以特定的日期

格式顯示出來。但是最近遇到了2038年後的日期顯示出問題了。如何解決呢? 


舊寫法 :


$date = date("Ymd",strtotime("2038-1-19"));

echo "2038-1-19 :" . $date . "<br />";     

使用日期(date)函式,結果顯示 2038-1-19 :20380119        


$date = date("Ymd",strtotime("2038-1-20"));

echo "2038-1-20 :" . $date . "<br />";   

使用日期(date)函式, 結果顯示 2038-1-20 :19700101            

由此看到日期(date)函式2038年1月20日之後的日期都無法正確顯示了


同樣要顯示日期增減也是會發生同樣的問題,當日期增加超過2038-1-20日,就無法顯示出來。

$this_date = Date("Ymd");

echo "today:" . $this_date . "<br />"; // 顯示 today:20210831


$date = date("Ymd",strtotime("+5985 days", strtotime($this_date)));

echo "add 5985 days:" . $date . "<br />"; // 顯示 add 5985 days:20380119


$date = date("Ymd",strtotime("+5986 days", strtotime($this_date)));

echo "add 5986 days:" . $date . "<br />";  // 顯示 add 5986 days:19700101        

    

怎麼解決2038年的限制呢?


您必須改用DateTime函式來取得日期(將日期字串轉成日期),並用format函式以特定的日期格式

顯示出來

$date =  new DateTime($this_date);


日期的增加則使用add函式

$date->add(new DateInterval("P6000D"));  // P開頭代表日期,6000D 代表 6000 天

echo "add 6000 days:" . $date->format("Ymd"); // add 6000 days:20380203

 

2020年12月8日

PHP解決錯誤訊息 "preg_replace(): The /e modifier is deprecated, use preg_replace_callback instead"的方法

作者: Fred F.M. Wang (FW知識瑣記) 日期: 2020/12/8

Codeigniter 搭配PHP 5.5版時,前端程式(View)送出(Submit)表單資料到後台程式(controller)

時發生錯誤訊息  core\Security.php : "preg_replace(): The /e modifier is deprecated, use 

preg_replace_callback instead"


錯誤的程式 : \system\core\Security.php 

錯誤的行: line 152, 153

$str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str);

return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str);


原因 : /e 修飾符在PHP 5.5中已經棄用, 要用preg_replace_callback()取代


查到PHP官網的解釋

/e修飾符在PHP 5.5已不推薦使用會產生Warning, 在PHP 7已經移除, 因為它很容易產生安漏

洞,可以使用preg_replace_callback()取代

   

官網說明內容如下 (ref : https://www.php.net/manual/zh/reference.pcre.pattern.modifiers.php)

因此Codeigniter系統的 \system\core\Security.php程式中line 152, 153

$str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str);

return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str);


要改寫成

$str = preg_replace_callback('~&#x(0*[0-9a-f]{2,5})~i', function($m){ return chr(hexdec($m[1])); }, $str);

return preg_replace_callback('~&#([0-9]{2,4})', function($m){ return chr(hexdec($m[1])); }, $str);


如此問題就解決了。


2020年9月7日

PHP程式設計: PHP程式如何將圖片放入excel檔案中 Using PHPExcel

作者: Fred F.M. Wang (FW知識瑣記) 日期:20200907

PHP程式中可以使用PHPExcel讀取製作好的Excel樣板,根據條件動態寫入資料,產生新的Excel檔案,用於產生Excel報表檔。

如果要根據不同條件放入不同的簽名圖片檔要怎麼做?

可以參考下面範例 : 

// 主程式

$objPHPExcelOut = PHPExcel_IOFactory::load($outfilepath); // $outfilepath寫入的Excel檔案路徑

$PHPExcelWriter = PHPExcel_IOFactory::createWriter($objPHPExcelOut, "Excel2007");

….

<寫入資料>

.....

 $row = 30;

 $signcol = "E";

 $offsetX = 27;

 $offsetY = 10;    

// 寫入簽名檔

 $this->addSignImage($objPHPExcelOut,$signcol,$row,$offsetX,$offsetY);



/* *****  副程式:寫入簽名檔 ***** */

private function addSignImage($objPHPExcelOut,$column,$row,$offsetX,$offsetY) {

    $signimgfile = dirname($_SERVER["SCRIPT_FILENAME"]) . "<圖片來源檔案路徑>";   

// <圖片來源檔案路徑與檔名> 例如"/files/shipinf/templates/image_imqsign.png"     

    $gdImage = imagecreatefrompng($signimgfile);    

    

// 保持PNG圖片背景透明

    imagealphablending($gdImage, false);  // 關閉 alpha 渲染

    imagesavealpha($gdImage, true); // 並設置 alpha 標誌以在保存 PNG 圖像時保存完整的 

alpha 通道資訊

    

    $objDrawing = new PHPExcel_Worksheet_MemoryDrawing();                

    $objDrawing->setName("signimage");

    $objDrawing->setDescription("signimage");

    $objDrawing->setImageResource($gdImage);      

$objDrawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_PNG);

    $objDrawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_DEFAULT);

    $objDrawing->setCoordinates($column.$row);    // 圖片左上角放置在哪個儲存格的位置

    $objDrawing->setHeight(390);   // 設定圖片高度(寬度會等比例變寬)

    $objDrawing->setOffsetX($offsetX);  // 向左位移幾個像素

    $objDrawing->setOffsetY($offsetY); // 向下位移幾個像素

    $objDrawing->setWorksheet($objPHPExcelOut->getActiveSheet());        

}




2020年8月20日

[輸入判斷] PHP判斷前端Checkbox欄位是否勾選

作者: Fred F.M. Wang (FW知識瑣記) 日期:20200820

 PHP程式接收前台網頁輸入的值,比較容易發生錯誤的是checkbox欄位,不像其他類型的輸入欄位

可以單純用$_POST['<field name >']接收輸入值那麼簡單。


前端的一個checkbox輸入欄,如果沒有勾選,則該表單submit後,後台PHP處理程式無法接收到此欄位的內容,因此判斷checkbox輸入欄是否有勾選,要用

isset($_POST['<field name >'])來判斷,如下面範例:


前端HTML

<form action="getcheckbox.php" method="post">

     Only Weekend<input type="checkbox" name="wkend" value="weekendonly">

     <input type="submit" value="submit">

</form>


後端PHP

<?php

$wkend = false;

if(isset($_POST['wkend'])) {

    $wkend = true;

    echo "weekly only checked";

} else {

    echo "Not check weekly only";    

}

?>

 

 

2020年7月31日

PHP二維key-value陣列根據特定欄位內容去除重複資料

作者: Fred F.M. Wang (FW知識瑣記) 日期: 2020-7-31

PHP一維陣列要移除重複的內容,很簡單只要使用array_unique函式即可

例如 :

$input = array("green", "red", "green", "blue", "red");

$result = array_unique($input);

結果$result內容為array( "green", "red", "blue");


二維的key-value陣列要根據特定欄位內容移除重複,要如何處理?


下面是多維(key-value)陣列 :  

items[0][“fieldname1”] = …;

items[0][“fieldname2”] = …;

items[0][“fieldname3”] = …;

items[0][“fieldname4”] = …;

…

items[0][“fieldnamen”] = …;


items[1][“fieldname1”] = …;

items[1][“fieldname2”] = …;

items[1][“fieldname3”] = …;

items[1][“fieldname4”] = …;

…

items[1][“fieldnamen”] = …;

….


要去除上面陣列 fieldname1, fieldname2, fieldname3欄位內容相同的item, 程式如下 :  


$new_items = array();

$keys = array();

if(!empty($items)) {

    foreach($items as $key => $rec) {

       $reckey = array($rec["fieldname1"],$rec["fieldname2"],$rec["fieldname3"]);

       if(!in_array($reckey,$keys)) {

           $keys[] = $reckey;

           $new_items[] = $rec;    

       }        

    }    

}

$items = $new_items;

2020年7月20日

PHP程式解決記憶體不足的錯誤 "Allowed memory size of ... bytes exhausted"

作者: Fred F.M. Wang (FW知識瑣記) 日期: 2020/7/20

PHP程式執行時發生下面錯誤
Fatal error: Allowed memory size of ... bytes exhausted (tried to allocate ... bytes) in  ….
表示是可用記憶體已耗盡。
可透過兩種方法解決 :
1、修改php.ini
例如 : memory_limit = 128
這種方法需要重啟web服務器。

2、在程式中使用ini_set函數修改設訂選項值
例如 : ini_set ('memory_limit', '128M')

如果一直加大記已體還解決不了問題,那麼可能程式中發生幾種無限耗用資源的情況
1 無窮的迴圈 : 迴圈中持續分配記憶體,例如增加陣列大小
2 無窮的遞迴程式 : 遞迴程式沒有寫好結束的條件。

3 使用了過大的陣列或過多的變數 (註 : 程式中不再用到陣列或變數,可使用unset()或$var = null釋放記憶)

好好檢查程式吧!

2020年6月29日

PHPExcel如何在工作表內放入ㄧ個圖片(背景是透明的PNG檔)

作者: Fred F.M. Wang (FW知識瑣記) 日期:2020/6/29

前ㄧ篇文 "PHPExcel 無法儲存寫入內含圖片的Excel檔,問題如何解決?",解決在儲存有Logo圖片的工作表問題後,另一種情況就是除了Logo外,還要加入一張圖片,而且圖片為背景是透明的PNG檔。嘗試後,分享程式如下 :

private function addSignImage($objPHPExcelOut,$column,$row) {
    $signimgfile = dirname($_SERVER["SCRIPT_FILENAME"]) . "/資料夾名稱/檔名.png";           
    $gdImage = imagecreatefrompng($signimgfile);   
   
     // 保持PNG圖片背景透明
    imagealphablending($gdImage, false);  // 關閉alpha渲染
    imagesavealpha($gdImage, true); // 設置alpha標誌以在儲存PNG圖像時保存完整的alpha通道資訊
   
    $objDrawing = new PHPExcel_Worksheet_MemoryDrawing();               
    $objDrawing->setName("signimage");
    $objDrawing->setDescription("signimage");
    $objDrawing->setImageResource($gdImage);
    $objDrawing->setRenderingFunction(PHPExcel_Worksheet_MemoryDrawing::RENDERING_PNG); 
    $objDrawing->setMimeType(PHPExcel_Worksheet_MemoryDrawing::MIMETYPE_DEFAULT);
    $objDrawing->setCoordinates($column.$row);    // 圖片左上角放置在哪個儲存格的位置
    $objDrawing->setHeight(390);   // 設定圖片高度(寬度會等比例變寬)
    $objDrawing->setOffsetX(288);  // 向左位移幾個像素
    $objDrawing->setOffsetY(14);   // 向下位移幾個像素
    $objDrawing->setWorksheet($objPHPExcelOut->getActiveSheet());       
}

主程式
$objPHPExcelOut = PHPExcel_IOFactory::load($outfilepath);
$objPHPExcelOut->setActiveSheetIndex(0);    // 預設0是指第一個工作表
.....
$col = "D";
$row = 27;
$this->addSignImage($objPHPExcelOut,$col,$row);

2020年5月29日

PHPExcel 無法儲存寫入內含圖片的Excel檔,問題如何解決?

作者: Fred F.M. Wang (FW知識瑣記) 日期:20200529


PHPExcel是一個PHP程式中用來存取Excel檔案很好用的程式庫。

我常常用套表的方式產生Excel檔報表,也就是事先建立一個Excel樣板格式檔,將格式調整好,如標題,表格標頭,欄寬欄高,表格框線,列印格式等設定在樣本檔中。然後,在PHP程式中,複製此樣本檔產生目的檔案,在將資料寫入目的檔案內。

最近發現的問題是,如果樣版格式內有圖片,例如公司Logo等,在資料寫入欄位,使用$objWriter->save($filename);要儲存時,就會發生錯誤訊息。

上網找尋答案,最佳的解法如下 :

原來這是PHPExcel "\PHPExcel\Writer\Excel2007.php"中的一個bug。

只要註釋掉或刪除第235-237行這三行程式碼(如下),問題就解決了
if (file_exists($pFilename)) {
   unlink($pFilename);
}

2020年4月15日

CodeIgniter架站如何與Windows AD Server認證帳號密碼?

作者: Fred F.M. Wang (FW知識瑣記) 日期:2020/4/15

企業內用CodeIgniter架站,通常需要整合公司內部的帳號系統,特別是很多企業常用的Windows AD Server。如何做到呢?

到github下載一個Auth_AD程式庫 - 這是一個基於CodeIgniter架構簡易的AD認證程式庫

其中包含三個檔案放在CodeIgniter 專案 'application' 的資料夾:
 config/auth_ad.php
 controllers/Auth.php
 libraries/Auth_AD.php


說明如下 :
一 設定檔 - config/auth_ad.php
   設定AD的認證網址與登入帳密。

二 Controller - controllers/Auth.php
    登入處理與登出處理,
   也可以客製加上記住帳密的程式(有空再分享) 。

三 libraries/Auth_AD.php  
    AD認證程式庫,
    也可以客製加上測試帳號密碼的認證(可以是自訂於AD之外的帳密資料表) ,測試環境與正式環境也可以有不同的處理(有空再分享)。


上面的程式也可以自己修改,客製符合您的需求。

在您網站,輸入帳號密碼的登入網頁中,Form action呼叫上面controller "auth.php"中的login函式,
如 echo form_open("auth/login”);


2020年4月10日

[繁簡中文並存問題]PHP Web應用系統繁簡中文並存問題研究

作者: Fred F.M. Wang (FW知識瑣記) 日期:2020/4/10

PHP Web應用系統無法繁簡中文並存的問題,陸續花了一些時間研究,下面是幾個結果!
一 檔案
我上網研究了一下,在PHP Web應用系統上傳簡體檔名的附件檔名會變成亂碼的,答案是無解。
PHP 將Big5檔名(繁體)的檔案存入到Windows檔案系統(繁體中文版)沒有問題,而對包含簡體字的Unicode(UTF-16)檔名的檔案,要存入到Windows檔案系統(繁體中文版)
,則無法處理。
註:php 7.1 才支援Unicode(UTF-16)
如果要解決這個問題,其實可以繞過編碼問題,透過設計的手法解決,請參考我的另一篇PO文: 
[繁簡中文並存問題]網頁應用上傳檔案檔名變成亂碼的解決方法 
 
二 SQL Server資料庫
一篇微軟官網的文章"說明SQL Server 中儲存 UTF-8 資料", 
提到"某些應用程式 (特別是 Web 應用程式) 必須處理以 UTF-8 編碼方法所編碼的 Unicode 資料會有
問題,因為SQL Server使用Unicode 編碼方式 (UCS-2),無法將 UTF-8 識別為有效的字元資料。
PHP Web應用系統 讀入鼎新ERP中的簡體中文資料無法轉換UTF-8編碼,顯示在PHP Web應用系統
上。
註:SQL Server 2019才支援UTF-8

三 mySQL資料庫
改用mySQL資料庫,繁簡中文都可以輸入與存取

所以如果使用PHP 7.1以前的版本,資料庫用SQL Server 2019以前的版本,PHP Web應用系統要完
全繁簡並存,是做不到的。