PHP搜尋陣列時,明明第一項就是要找的商品代碼,程式卻顯示「找不到」?先看你是不是把array_search()的結果直接放進if。它回傳的是鍵,不是單純的成功或失敗:找到第一項時,鍵可能是整數0;沒找到才回傳布林值false。 先把回傳值印出來 用一個普通的商品代碼清單就能重現。將下面存成獨立PHP檔執行,先觀察var_dump顯示的型別。 <?php $codes = ['starter', 'pro', 'team']; $key = array_search('starter', $codes, true); var_dump($key); // int(0) if ($key) { echo "找到\n"; } else { echo "找不到\n"; // 這個判斷寫錯了 } 這裡搜尋已成功,問題出在後面的條件。整數0在布林判斷中會被當成false,所以不能用if ($key)辨認搜尋是否成功。也不要改成if (!$key)或$key == false,它們同樣會把0混進失敗分支。 只把布林false當成沒找到 需要拿回鍵來讀取或處理那一項時,明確比較回傳值是否為布林false。下面是可替換前例的完整版本。 <?php $codes = ['starter', 'pro', 'team']; $key = array_search('starter', $codes, true); if ($key !== false) { echo '找到鍵:' . $key . "\n"; echo '商品代碼:' . $codes[$key] . "\n"; } else { echo "找不到\n"; } 這次會輸出鍵0及商品代碼starter。找不到時則走else。如果要用unset($codes[$key])移除匹配項,也應放在這個成功分支裡;不要在確認結果前就把false拿去當陣列鍵,否則可能誤操作鍵0。 第三個參數true,解決的是型別匹配 array_search的第三個參數和後面的!== false各有用途。前者要求搜尋值與陣列項目型別一致,後者分清「找到鍵0」和「沒有找到」。加了第三個參數,仍不能省略結果判斷。 <?php $ids = ['12', 12];...
2026-10-14 68 0
文尼先生 2026-10-14

PHP讀取JSON後得到null,不一定表示解碼失敗。JSON本身可以是一個合法的null;但格式錯誤時,預設的json_decode()也可能回傳null。若程式只寫「結果為null就報錯」,便會把有效資料當成錯誤。需要可靠區分時,可以用JSON_THROW_ON_ERROR,把解碼失敗交給JsonException處理。 這個問題容易出現在匯入檔案、第三方API回應及儲存JSON設定的功能裡。畫面只顯示「資料是空的」,站長卻不知道是服務正常回傳空值,還是資料傳到一半壞掉。先把語法解析與資料格式檢查拆開,錯誤訊息才會說到真正的問題。 合法null和壞掉的字串長得不一樣 JSON的null不需要引號,也沒有大括號。字串'null'交給json_decode後會成為PHP的null。相反,'{"name":}'缺少值,屬於無效JSON。預設解碼這兩者,都可能得到相同的null結果,只看回傳值無法分辨。 空字串也不是JSON的null。API回應沒有內容、HTTP請求失敗、檔案讀取失敗和伺服器回傳HTML錯誤頁,各自有不同原因;不能把它們先改成'null'再繼續處理。應先確認讀取或請求成功,再把真正拿到的字串交給解析器。 JSON也不只允許物件或陣列。像false、0和一段有雙引號包住的字串,都可以是合法值。因此「解碼沒有拋例外」只證明語法能解析,還不能證明資料符合某個API要求的物件結構。 用四組輸入看清差別 以下程式只使用合成字串,可儲存為case.php後在命令列執行。JSON_THROW_ON_ERROR自PHP7.3提供;本文的輸出來自PHP8.4.2。先用普通模式記錄錯誤,再用例外模式解析同一份資料。 <?php $cases = [ 'valid-null' => 'null', 'valid-object' => '{"name":"demo"}', 'broken' => '{"name":}', 'empty' => '', ]; foreach ($cases as $label => $raw) { $plain = json_decode($raw, true); $error = json_last_error(); printf("%s plain=%s error=%d\n", $label, var_export($plain, true), $error); try { $value = json_decode($raw, true, 512, JSON_THROW_ON_ERROR); echo "throw-mode: ", var_export($value, true), PHP_EOL; } catch (JsonException $e) { echo "throw-mode: JsonException code=", $e->getCode(), PHP_EOL; } } 合法null在普通模式的錯誤碼為0,例外模式仍然回傳null,沒有進入catch。合法物件會得到包含name的陣列。壞掉的字串與空字串在這組測試裡都得到語法錯誤碼4,例外模式則拋出JsonException。寫應用程式時應用JSON_ERROR_NONE等常數判斷,不要把這些數字硬寫成你的業務規則。 這樣你就能把「資料確實是null」與「資料無法解碼」放到不同分支。若對方的API規格允許null代表沒有設定,便可以在成功解析後處理這種狀態;若規格要求物件,則回報資料結構不符,而不是誤報語法壞掉。 把解析放在一個小的try區塊 try { $data =...
2026-10-04 63 0
文尼先生 2026-10-04

PHP 官方於 2026 年 10 月 21 日發布緊急安全更新,修補俗稱 PHP2Shell 的兩個高危漏洞。使用 WordPress 的站長,現在要向主機商確認的是:網站實際使用的 PHP 是否已套用修補,以及更新後的工作程序是否已重新啟動。只在 WordPress 後台按下核心、主題或插件更新,無法完成這次 PHP 執行環境的修補。 PHP2Shell 影響哪些網站? 這次涉及 CVE-2026-109618 與 CVE-2026-109619,官方預告列出的 CVSS v4.0 評分均為 9.2。問題出在 PHP 核心處理請求與記憶體的方式,可能讓未登入的遠端攻擊者執行程式碼。 PHP 官方把所有提供網頁請求的 PHP 安裝列為風險範圍,包括 PHP-FPM、Apache 的 mod_php、php-cgi、FrankenPHP 與 LiteSpeed。當中 mod_php 的風險被列為最高,已有在應用程式碼執行前觸發攻擊的示範。因此,網站有登入頁、關閉會員註冊,或沒有讓訪客上傳檔案,都不能直接當成安全判定。 兩份上游公告分別描述記憶體耗盡時的狀態損壞,以及前一次請求留下的全域狀態引用了已釋放的記憶體。這也解釋了為何處理範圍會超出單一 WordPress 插件:維護者需要檢查主機上的 PHP 本身。 先對照分支,再確認修補來源 PHP 官方已發布下列修補版本;若採用上游版本,請更新至所屬分支的這個版本或更新版本。 PHP 8.2:8.2.35。 PHP 8.3:8.3.36。 PHP 8.4:8.4.27。 PHP 8.5:8.5.12。 由 Linux 發行版或長期支援供應商維護的套件,可能採用回移補丁:保留原本的基礎版本號,把安全修正加進套件。例如 Ubuntu 官方列出,24.04 的修補套件為 8.3.6-0ubuntu0.24.04.13,22.04 則為 8.1.2-1ubuntu2.28。不能因為畫面仍顯示 8.3.6,就斷定它一定沒有修補;也不能只聽到「有自動更新」就認定完成。請核對完整套件版本和供應商公告。 PHP 8.1 及更舊版本已不再獲得 PHP 專案的正常更新。官方這次提供了 7.4、8.0、8.1 的最小原始碼回移修補,供特定維護情境使用,並不代表這些分支恢復支援。若主機商無法提供相應修補,應安排遷移至仍受支援的 PHP 版本,先確認網站、主題與插件的相容性。 WordPress 站長可以怎樣向主機商確認? 先登入自己的 WordPress...
2026-10-21 61 0
文尼先生 2026-10-21

表單送來一個欄位,值剛好是null;後端卻回報「沒有這個欄位」。遇到這種情況,先看程式是不是用了isset()。它同時要求變數存在、值不是null,不能單靠結果判斷陣列裡有沒有這個鍵。要區分「沒傳」與「明確傳null」,應先用array_key_exists()判斷鍵,再處理值。 這個差別常出現在設定更新、資料匯入及API部分更新。例如使用者要清除副標題,系統把null當成清空指令;若後端把null視為未提供,就會保留舊副標題。本文用普通PHP陣列拆開這兩種情況,讓判斷對應到你真正要處理的動作。 先把「有鍵」與「有值」分開看 假設收到的資料是['subtitle' => null]。subtitle這個鍵確實在陣列裡,但它沒有非null的值。array_key_exists('subtitle', $input)會得到true,isset($input['subtitle'])則得到false。兩個結果都符合PHP的規則,只是它們回答不同的問題。 如果資料是空陣列,兩種檢查都得到false。也就是說,只看isset的false,無法知道欄位缺席,還是欄位存在但值為null。這不是資料自動被刪掉,也不是PHP沒有讀到請求;是你的檢查方式把兩種狀態合在一起。 還要留意空字串、數字0及布林false。這些值都不是null,所以isset會得到true。把isset當成「有填內容」也容易出錯:空字串可以通過isset,卻未必符合你的表單規則。鍵是否存在、值是否可接受,應分成兩個判斷。 用五組資料確認結果 建立一個獨立的case.php,貼上以下程式。它只檢查記憶體裡的陣列,不連接資料庫,也不會修改網站設定。執行前確認你使用的PHP命令指向要測試的版本。 <?php $cases = [ 'missing' => [], 'null' => ['subtitle' => null], 'empty' => ['subtitle' => ''], 'zero' => ['subtitle' => 0], 'false' => ['subtitle' => false], ]; foreach ($cases as $name => $input) { printf("%s: exists=%s isset=%s\n", $name, array_key_exists('subtitle', $input) ? 'true' : 'false', isset($input['subtitle']) ? 'true' : 'false'); } 在PHP8.4.2執行php case.php,輸出如下。最值得留意的是第二行:鍵存在,但isset仍然為false。後三行則說明不能把空字串、0、false和null混成同一種狀態。 missing: exists=false isset=false null: exists=true isset=false empty: exists=true isset=true zero: exists=true isset=true false: exists=true isset=true 如果你的結果不同,先看測試資料是否真的保留null。有些表單流程會把空白欄位轉成null,也有資料處理層會先移除值為null的鍵。檢查的位置很重要:應在你要判斷的那個資料結構上測,而不是只看更早收到的原始字串。...
2026-10-04 59 0
文尼先生 2026-10-04

把兩批文章標題放進陣列,用$left + $right合起來,結果右邊第一筆不見了。PHP陣列的加號是按鍵名做聯集,不是把所有值接到後面。兩邊有相同鍵名時,左邊的值會留下,右邊對應的值會被忽略。 兩個列表都從0開始,第一個鍵就撞上了 以下每段都是獨立PHP範例,可各自存成.php檔執行。註解列出預期輸出,資料只是示例字串。 <?php $left = ['header', 'footer']; $right = ['sidebar']; echo json_encode($left + $right), PHP_EOL; // ["header","footer"] echo json_encode(array_merge($left, $right)), PHP_EOL; // ["header","footer","sidebar"] left的鍵是0、1;right的鍵也是0。因此,sidebar與header搶的是同一個鍵,加號保留左邊的header,並不是按文字內容去除重複。若只是要把兩批列表依序接起來,array_merge會保留三個值,並把整數鍵從0重新編號。 字串鍵相同時,兩種寫法的優先順序相反 <?php $left = ['color' => 'blue', 'rows' => 12]; $right = ['color' => 'red', 'cache' => true]; echo json_encode($left + $right), PHP_EOL; // {"color":"blue","rows":12,"cache":true} echo json_encode(array_merge($left, $right)), PHP_EOL; // {"color":"red","rows":12,"cache":true} 加號保留左邊color的blue;array_merge則由後面的red覆蓋前面的值。右邊獨有的cache,在兩種結果裡都會出現。合併網站設定時,先決定同鍵衝突要由誰優先,再選寫法;交換左右位置也會改變結果。 這個例子只處理一層鍵值。巢狀設定裡若還有陣列,不能直接把它當成逐層遞迴合併。 數字是文章ID時,不要順手重編鍵名 <?php $left = [101 => 'Article A']; $right = [202 => 'Article B']; echo json_encode($left + $right), PHP_EOL; //...
2026-10-24 55 0
文尼先生 2026-10-24

第一輪foreach改完價格,資料明明是11、21、31;接著只是再走訪一次,最後一項卻變成21。若前一輪寫了&$price,先查迴圈結束後有沒有unset($price)。引用不會隨著右大括號自動解除,後面再用同一個變數,就可能改到陣列尾項。 第二輪看似只讀,為何改了尾項 把下面程式存成PHP檔執行。第一輪透過引用替每個值加1,第二輪沒有寫任何更新陣列的程式,卻仍會改變結果。 <?php $prices = [10, 20, 30]; foreach ($prices as &$price) { $price += 1; } echo json_encode($prices), PHP_EOL; // [11,21,31] foreach ($prices as $price) { // 這裡沒有主動修改陣列 } echo json_encode($prices), PHP_EOL; // [11,21,21] 第一輪結束時,$price仍連著$prices最後一項。第二輪雖然沒有&,每次把元素值指派給$price,仍會透過殘留引用寫進尾項;輪到最後一項時,它已被前面的21覆蓋。問題不是json_encode,也不是陣列排序。 引用用完,立即解除連結 在引用迴圈結束後加上unset($price),再開始下一輪。用完整程式重新執行,避免前一次實驗留下的引用干擾結果。 <?php $prices = [10, 20, 30]; foreach ($prices as &$price) { $price += 1; } unset($price); foreach ($prices as $price) { // 後續一般走訪 } echo json_encode($prices), PHP_EOL; // [11,21,31] 這裡unset的是引用變數$price,解除它與陣列元素的連結,不是刪除$prices的最後一項。不要誤寫成unset($prices[2]),那會移除元素。第一輪已完成的加1結果,也不會因為解除引用而還原。 不需要引用,就明確按key回寫 若只是更新每一項,可以改用key指定位置,把引用的生命週期問題拿掉。 <?php $prices = [10, 20, 30]; foreach ($prices as...
2026-10-20 54 0
文尼先生 2026-10-20
顯示驗證碼
沒有帳號?註冊  忘記密碼?