發表文章

目前顯示的是有「PHP」標籤的文章

[PHP][AI] 免費token吃到飽 超簡單開源模型PHP應用實例 (包含 Ollama 的安裝與使用教學)

在 AI 百花齊放的今天,各家大模型很好用想必大家都已經知道了。隨之而來的各種訂閱費用,想當個免費仔越來越難。如果只是公司內網系統中的一個小小 AI 應用(例如:翻譯),其實免費的開源本地模型就夠了,不用訂閱費,token 還可以吃到飽,使用方法也很簡單。 第一步:安裝管理本地模型的工具【Ollama】 想要使用開源的本地模型,你需要先有管理模型的工具,我們這邊選擇很多人愛用的 Ollama 。 Ollama 是一個讓你在本地端(Local)輕鬆執行、管理開源大型語言模型(LLM)的工具。它將模型權重、設定和依賴環境打包在一起,讓你可以直接在終端機透過簡單的指令快速啟動 AI。 1. 安裝 Ollama: 最快的方式是直接透過終端機指令安裝。 curl -fsSL https://ollama.com/install.sh | sh 2. 下載並執行模型: 安裝完成後,你可以直接下達 run 指令。如果本地端沒有該模型,Ollama 會自動幫你從 registry 下載。以 Google 最新的開源模型 Gemma4 為例:(e4b-it-q4_K_M 是版本號,可以視本地主機規格選擇適合的版本 https://ollama.com/search ) ollama run gemma4:e4b-it-q4_K_M 隨時間推移,你可能會下載許多模型。你可以用 list 去查看目前下載了哪些模型 ollama list 假設你除了 gemma4 之外,也下載了 qwen2.5:7b 這個模型,後來覺得 qwen2.5 不需要了,可以用 rm 移除,避免佔用空間。 ollama rm qwen2.5:7b 第二步:啟動本地模型的服務 我們在上一步的操作中,成功的在本地主機上裝好了 Ollama,也一併下載了 Google 免費開源模型 Gemma4 之後(只有第一次時需要), 請將本地主機重新開機 。 開機後本地主機不會主動啟動 Ollama 的服務,我們可以透過以下指令啟動服務: OLLAMA_HOST="0.0.0.0:11434...

[MAC][Vim][PHP] MacBook 升級到 macOS Tahoe 後 Vim 配色跑掉的解決方式

最近將 MacBook 的系統從 macOS Sequoia 升級到 macOS Tahoe 後,意外發現原本使用的 Vim colorscheme default 配色突然跑掉。許多語法的顏色變淡、變灰,尤其是在 PHP 編輯時常用的語法高亮根本不見了。 研究後發現主要原因是: macOS Tahoe 的終端機預設啟用了新的色彩處理方式 Vim 在沒有指定 termguicolors 時會退回較舊的顏色模式 也就是說: 系統升級後,Vim 沒有自動使用 True Color(真彩色)模式,造成 default colorscheme 顯示異常。 🔧 解決方式:啟用 True Color 並重新定義需要的語法高亮 在 ~/.vimrc 中加入: set termguicolors 這行設定會強制啟用 24-bit True Color,讓 Vim 能正確顯示舊版系統相同的配色呈現。 接著,我針對自己常用的 PHP 語法補回原本舊版的配色: " 行號 (Line Number) highlight LineNr guifg=#DAA520 guibg=NONE " 搜尋 (Search) highlight Search guifg=#FFFFFF guibg=#FF0000 " PHP 語法高亮 highlight phpStatement guifg=#DAA520 highlight phpOperator guifg=#DAA520 highlight phpVarSelector guifg=#DAA520 highlight phpComparison guifg=#DAA520 highlight phpNumber guifg=#DAA520 highlight phpMethodsVar guifg=#FFFFFF highlight phpIdentifier guifg=#00CCCC highlight phpStringSingle guifg=#FF4500 highlight phpStringDouble guifg=#FF4500 highlight phpConditional...

[PHP][MYSQL] PHP+MySQL 批量更新百萬級資料的最佳策略

在處理數十萬甚至數百萬筆資料的更新任務時,許多開發者習慣使用迴圈執行單條 UPDATE 語句。但當資料量過大時,這種做法會導致應用程式卡死、資料庫負載飆升,效率極低。 本文將介紹一種資料庫專業人士常用的高效解決方案: 使用 UPDATE JOIN 搭配臨時表(Temporary Table) 。 🎯 什麼是批量更新的「效能殺手」? 當您使用 PHP 迴圈執行 10 萬次 UPDATE ... WHERE id = X 時,主要的效能瓶頸並不是資料庫處理本身,而是: 網絡傳輸延遲: 10 萬次 PHP 應用伺服器與 MySQL 伺服器之間的通訊。 SQL 解析開銷: MySQL 必須解析、驗證和優化 10 萬次 SQL 語句。 磁碟 I/O 寫入: 缺乏事務(Transaction)保護下,每一次更新都可能觸發一次昂貴的磁碟日誌寫入。 我們的目標是將這 10 萬次操作,轉換為 一次高效、單一的資料庫操作 。 💡 最佳策略:UPDATE JOIN + 臨時表 這個策略的核心思路是: 收集新值: 將所有需要更新的新資料(例如 uid 和 name )組裝起來。 快速載入: 將這些新值一次性快速載入到一個輕量級的 臨時表 中。 單次執行: 執行一個高效的 UPDATE JOIN 語句,讓資料庫在內部利用索引完成所有幾十萬筆資料的更新。 適用情境 異質更新: 每筆資料要更新的目標值都不同(例如:客戶 A 積分變 100,客戶 B 積分變 200)。 非唯一鍵更新: 主表中的關聯鍵(如您的 uid )可能 重複 。 🛠️ 實戰教學:三步驟完成百萬級更新 假設我們有一個名為 performance_records 的業績表, uid 欄位會重複,我們需要根據新的清單來更新所有匹配的 name 欄位。 步驟 1:建立並填充臨時表 (使用 PHP 批量 INSERT) 我們首先建立一個臨時表 temp_name_updates ,並將幾十萬筆新資料高效地寫入。 關鍵優化: 在臨時表上建立 主鍵 ( PRIMARY KEY ) ,這能極大地加速稍後的 JOIN 關聯速度。 // 假設 $pdo...

[PHP][jQuery] 如何利用 jQuery 的 inArray 來判斷資料是否存在於陣列中 (類似 PHP in_array 的效果)

在前後端互動的網頁應用中,常見需求是後端 PHP 傳送資料陣列到前端,再由 jQuery 判斷使用者輸入的值是否存在。以下是簡單實作方式。 1. PHP 將陣列轉為 JSON <?php $arr_list = array("S0001", "S0002", "S0003"); $json_list = json_encode($arr_list); ?> <script> var erpidArray = <?php echo $json_list; ?>; </script> 說明: 使用 json_encode() 將 PHP 陣列轉成 JavaScript 可讀的 JSON 格式。如果$arr_list是空陣列也沒關係,因為json_encode會將空陣列轉成[],這對前端來說也是空陣列的意思,在JS的部分不會報錯。 2. jQuery 判斷值是否存在 var userInput = 'S0002'; if ($.inArray(userInput, erpidArray) > -1) { alert("存在於陣列中!"); } else { alert("不存在於陣列中。"); } 補充: 如果要判斷找不到的情形 可以用 if ($.inArray(userInput, erpidArray) === -1) { 。

[PHP] 如何利用 cURL 實現自動排程

在開發 PHP 專案時,有時會需要定時從某個 API 或網站抓取資料,例如每日更新匯率、天氣預報,或備份遠端資料。這類需求可以透過 PHP 的 cURL 函式來完成抓取動作,再搭配 Linux 的 cron 排程功能,就能達到「自動執行」的效果。 以下將介紹如何用 PHP 的 cURL 撰寫一支簡單的資料抓取程式,並教你如何設定排程,讓它自動定時執行。 範例程式碼:用 cURL 抓取資料的函式 <?php /** * 透過 cURL 從指定 URL 獲取內容。 * * @param string $url 要獲取內容的目標 URL。 * @param int $timeout (可選) cURL 連線的超時時間,單位秒。預設為 30 秒。 * @param bool $verifySsl (可選) 是否驗證 SSL 憑證。預設為 false (不驗證)。 * @return string|false 成功時回傳 URL 內容字串,失敗時回傳 false。 */ function fetchDataFromUrl(string $url, int $timeout = 30, bool $verifySsl = false) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_HEADER, 0); // 不包含響應頭部 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); // 將結果以字串回傳 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); // 設定超時時間 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verifySsl); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verifySsl ? 2 : 0); $content = curl_exec($ch); if (curl_errno($ch)) { $content = false; } cu...

[PHP] 如何解決 下載檔案的連結 因瀏覽器的快取(緩存) 無法下載到最新的檔案

//告訴瀏覽器不要緩存文件 header('Cache-Control: no-cache, no-store, must-revalidate'); // HTTP 1.1. header('Pragma: no-cache'); // HTTP 1.0. header('Expires: 0'); // Proxies. //下載 header('Location: myfile/myzip.zip');

[MYSQL][PHP] 如何不影響使用者操作 完成大資料表的更新

有些資料表需要每日更新,而更新過程需要一段時間,一般的作法是刪掉舊資料,然後寫入新資料,過程中使用者可能會因為舊資料被刪掉又還沒寫入新資料,導致系統產生錯誤。 為了避免發生這種情形,較好的更新資料策略為:

[PHP] 用程式檢查文字檔編碼是否為 "UTF-8 碼 (檔首有BOM)"

UTF-8 的文檔分為 "檔首有BOM" 及 "檔首無BOM" 兩種,如果遇到程式讀取使用者上傳的文檔,明明用記事本打開第一碼是A(舉例),但用程式讀內容抓到的第一碼卻不是A,可能這個檔案就是檔首含BOM的文件,檢查方式很簡單,如下....

[PHP] IE瀏覽器下載特殊附檔名檔案時(如 .nlbl檔) 會自動變成.zip檔

簡單的下載連結 <a href="abc.nlbl">NiceLabel檔案下載</a>  Chrome、Firefox 都可以正常下載,但 IE 下載時會自動改成 a.zip,可用下面的程式碼來設定 header,如下: <PHP的部分> if ($_GET['type'] == 'nlbl' && $_GET['file']) {   header('Content-Type: application/octet-stream');   header('Content-Disposition:attachment; filename = '.$_GET['file']);   readfile($_GET['file']); } <HTML的部分> <a href="?type=nlbl&file=abc.nlbl">NiceLabel檔案下載</a>

[PHP] 簡單DIY一支監測網站是否掛掉(hang或down)的程式 (配合cronjob或工作排程)

網站有時會因為各種原因掛掉(或半死不活網頁一直轉圈圈),因為server主機或服務還活著,有些網管監控軟體無法立即反映出問題,我們可以簡單寫一支小程式去監測網站的回應時間...

[PHP] 陣列的排序函式

圖片
效果 昇冪 降冪 使用者定義的順序 依值排序,然後重新指定從0開始的索引 sort() rsort() usort() 依值排序 asort() arsort() uasort() 依鍵排序 ksort() krsort() uksort() 備註:上面的排序法已經可以解決大部分的問題,PHP還有提供另一種非常符合人性的自然排序法,有分大小寫的natsort()與不分大小寫的natcasesort()兩種,如下: $arr = array("temp15.txt","Temp10.txt","temp1.txt","Temp22.txt","temp2.txt"); sort($arr); //基礎排序 無法正確排序帶文字的數字 eg. 1.jpg 10.jpg 2.jpg print_r($arr); natsort($arr); //自然排序 有區分大小寫 print_r($arr); natcasesort($arr); //自然排序 不區分大小寫 print_r($arr);

[PHP] 匿名函式(又稱閉包closure) 引用外部變數時,使用 global 與 use 的差異

以 usort() 來舉例,使用匿名函式的寫法如下... $array = array(200, 300, 100); usort($array, function($a, $b) { return $a > $b; }); print_r($array); //Array ( [0] => 100 [1] => 200 [2] => 300 ) 如果我們想用一個變數($bln)去決定升冪或降冪,寫法可以有以下兩種... 使用 global : $array = array(200, 300, 100); $bln = 1; usort($array, function($a, $b) { global $bln; if ($bln) { return $a $b; } }); print_r($array); //Array ( [0] => 300 [1] => 200 [2] => 100 ) 使用 use : $array = array(200, 300, 100); $bln = 1; usort($array, function($a, $b) use($bln) { if ($bln) { return $a $b; } }); print_r($array); //Array ( [0] => 300 [1] => 200 [2] => 100 ) 用 global 與 use 結果是相同的,但如果我們多包一層function的時候... $array = array(200, 300, 100); $bln = 1; function mysort($array) { $bln = 0; usort($array, function($a, $b) use($bln) { if ($bln) { return $a $b; } }); return $array; } $array = mysort($array); print_r($ar...

[PHP] exit()的用法 以及 與die()的差異

exit、exit()與exit(0)都可以讓程序結束,如果希望程序結束時印出字串,可以使用exit('Error'),至於die()就是exit()一模一樣的別名函式,常於連線資料庫時使用。 $con = mysql_connect("localhost","mysql_user","mysql_pwd"); if (!$con) { die('Could not connect: ' . mysql_error()); //等同 exit('Could...'); }

[PHP] if 的三種寫法

第一種 if (10 > 0) echo 'Yes'; //只能有一行 超過會報錯 else echo 'No'; 第二種 if (10 > 0) { echo 'Yes'; echo '...'; //可以有多行 } else { echo 'No'; echo '....'; } 第三種 if (10 > 0) : echo 'Yes'; echo '...'; else : echo 'No'; echo '...'; endif; 註1: 建議使用第二種寫法。 註2: 第三種寫法與第二種基本上相同,常見於HTML混寫時使用(例如:laravel的blade樣版)。 switch、while、for、foreach...也有類似的替代寫法 switch ($a) : case 'A': echo 'AAA'; break; endswitch; while ($i

[PHP] 如何將網頁表格(table)轉成Excel的xlsx檔 (使用PHPExcel)

先下載PHPExcel套件(這篇是用1.7.X版示範),然後程式碼如下... //程式碼大概就下面七行 ob_start(); include_once('PHPExcel.php'); $obj = new ExcelService(); $html_table = '<table><tr><td>123中文</td></tr></table>'; //要轉成Excel的表格 $html_table = mb_convert_encoding(html_entity_decode($html_table), 'HTML-ENTITIES', 'UTF-8'); //避免中文變成亂碼 $excelFile = $obj->generateExcel($html_table, 'myexcel', 'my_excel_folder'); //產生的Excel的檔名 並指定要放在哪個資料夾 ob_end_clean(); header('Location: my_excel_folder/myexcel.xlsx'); //固定的Class 可以不用改 class ExcelService { public function generateExcel($content, $fname, $tmp_path = '') { if ($fname == '') $fname = date('YmdHis'); if ($tmp_path == '') $tmp_path = 'temp'; $filename = $fname . '.xlsx'; $htmlname = $fname . '.html'; $excelFile = $tmp_path . '/' . $filename; $h...

[PHP] 如何將數個檔案進行打包 並產生ZIP壓縮檔 (使用PHP原生套件 ZipArchive )

假如需要數個檔案打包成一個壓縮檔,可利用PHP原生套件ZipArchive,使用方法很簡單,如下... //實際所需要的code大概就下面四行 $zip = new ZipArchive(); if ($zip->open('my_zip_folder/myzip.zip', ZipArchive::OVERWRITE) === TRUE) { //指定打包之後的壓縮檔要放在my_zip_folder下面 檔名為myzip.zip addFileToZip('my_file_folder/', $zip); //my_file_folder 就是我們要打包的資料夾 裡面必需有兩個以上的檔案才能打包 $zip->close(); } //產生ZIP檔後讓瀏覽器執行下載動作 header('Location: my_zip_folder/myzip.zip'); //固定的function 不用改 function addFileToZip($path,$zip){ $handler = opendir($path); //開啟當前資料夾由$path指定。 while (($filename = readdir($handler)) !== false) { if ($filename != "." && $filename != "..") { //資料夾檔名字為'.'和'..',不要對他們進行操作 if (is_dir($path."/".$filename)) { // 如果讀取的某個物件是資料夾,則遞迴 addFileToZip($path."/".$filename, $zip); } else { //將檔案加入zip物件 $zip->addFile($path."/".$filename); } ...

[PHP] 解決 「使用 Postman 產生的 PHP - cURL 程式碼,卻顯示空白畫面的問題」

圖片
Postman 的 Code 功能可以自動產生程式碼 (如圖一所示),理論上在 Postman 可以抓到資料,將程式碼貼到 PHP 也應該能夠抓到相同資料,但實際上卻只會顯示空白畫面,那是因為缺了一個SSL的CURL設定,加上後就可以抓到資料了(如圖二所示)。 CURLOPT_SSL_VERIFYPEER => false 

[LeetCode][PHP] #35 Search Insert Position

https://leetcode.com/problems/search-insert-position/ class Solution {     function searchInsert($nums, $target) {         if (array_search($target, $nums) !== false) {             return array_search($target, $nums);         }         else {             foreach ($nums as $k => $v) {                 if ($v > $target) {                     return $k;                 }                 else if (($k+1) == count($nums)) {                     return $k+1;                 }             }         }     } }

[LeetCode][PHP] #242 Valid Anagram

https://leetcode.com/problems/valid-anagram/ class Solution {     function isAnagram($s, $t) {         $a_s = str_split($s);         $a_t = str_split($t);         sort($a_s);         sort($a_t);         return implode('', $a_s) === implode('', $a_t);     } }

[LeetCode][PHP] #7 Reverse Integer

https://leetcode.com/problems/reverse-integer/ class Solution {     function reverse($x) {         $symbol = 1;         if ($x < 0) $symbol = -1;         $int = $x * $symbol;         $int = strrev($int) * $symbol;         if ($int > pow(2, 31) or $int < pow(2, 31)*-1) {            return 0;         }         else {             return $int;         }     } }