跳到主要內容

發表文章

修正 XOOPS 2.7 儲存頁尾註腳 HTML 會被自動過濾為純文字的問題

今天無意間又發現 XOOPS 2.7的一個BUG問題,就是儲存頁腳的資訊區塊,原本(XOOPS2.5.11)都還能支援HTML格式,現在貼入內容會被自動清除為純文字格式,這不處理會死人的呢!!頁腳聯絡資訊,網站資訊,還有AA標章,連CSS都沒辦法用,一堆HTML要放的,變成純文字能交差嗎。 經追查資料庫config存進去就已經被過濾成純文字了,研判因該是在儲存端的Xoops安全機制過濾的,於是再反查Xoops的modules/system/admin.php 最後在這裡找到 modules\system\admin\preferences 用筆記本打開找到約第439行 // Detect this and explicitly set an empty array instead. 吧下面整段註解掉 /* $multiFormTypes = ['select_multi', 'group_multi', 'user_multi', 'theme_multi']; if (in_array($formType, $multiFormTypes, true) && !Request::hasVar($confName, 'POST')) { $new_value = []; } else { $new_value = Request::getVar($confName, $config->getVar('conf_value'), 'POST'); }*/ 替換為 //修改儲存頁腳footer會被自動過成濾純文字的問題 $multiFormTypes = ['select_multi', 'group_multi', 'user_multi', 'theme_multi']; if (in_array($formType, $multiFormTypes, true) && !Request::hasVar($...

CSS LOGO 描邊陰影字工法(替換原 filter: drop-shadow)用法,解決行動瀏覽異常消電原問題(觸發 GPU 合成層)

之前寫過一篇【 用CSS做出來一個文字漸層+文字白框+文字陰影的LOGO區塊,CSS最終解法並符合無障礙 】的工作心得,但經過多次實際驗證,filter: drop-shadow方法雖然較為美觀,但在行動瀏覽或是平板,容易觸發 GPU 合成層,導致版面異常(畫面上下空白),裝置發燙等耗電等問題,因此經改良後,改用CSS LOGO 描邊陰影字工法能維持與原本 filter: drop-shadow相同的效果,且手機平版不會異常,方法如下: 以下是使用-webkit-text-stroke/text-shadow做出來的文字效果,幾乎能90%還原PSD設計效果 文字的PHP常數增加data-storke設定 define('_THEME_LOGO_02','<div class="logo_01_box" aria-hidden="true" tabindex="-1" data-storke="桃園市" >桃園市</div><div class="logo_02_box" aria-hidden="true" tabindex="-1" data-storke="快樂" >快樂</div><div class="logo_03_box" aria-hidden="true" tabindex="-1" data-storke="國民小學" >國民小學</div>'); 注意: aria-hidden="true":視覺文字不給讀報軟體讀。 - tabindex="-1":避免視覺文字進入 TAB 流。 data-storke:提供 CSS content:attr(data-storke); 使用。 外層已有可讀 aria-label 或 sr-only,不要讓同一段校名被讀兩次。 CSS 核心寫法 #toplogobox{ position:relative; width:980p...

修正 XOOPS 2.7 profile 模組編輯欄位時出現 Incorrect column name '' 問題

今天測試 XOOPS 2.7 的 profile 模組時,無意間發現後台欄位編輯有一個問題。 操作路徑:後台 → Profile 模組 → 欄位 → 編輯 只要修改任意一項後送出,就會出現錯誤: Errors field_name 為必填項 Incorrect column name '' MySQL 除錯訊息會看到類似這段: ALTER TABLE profile_profile ADD  varchar(255) NULL 一開始看起來很像資料表壞掉,因為 SQL 竟然要新增一個空白欄位名稱。但後來追程式才發現,真正原因不是資料表問題,而是表單送出時沒有把既有欄位的 id 傳回去。 XOOPS 2.7 的 modules/profile/admin/field.php 在儲存時會從 POST 讀取欄位 id: $fieldId = Request::getInt('id', 0, 'POST'); 如果 POST 沒有收到 id,系統就會誤判成「新增欄位」。但因為目前其實是在編輯既有欄位,表單中沒有 field_name 輸入框,最後就變成欄位名稱是空字串,進而產生: ADD  varchar(255) 修復方式 用文字編輯器打開:modules/profile/include/forms.php 找到 profile_getFieldForm() 裡建立表單的位置,大約在前段: $form = new XoopsThemeForm($title, 'form', $action, 'post', true); 在下方加入: if (!$field->isNew()) { $form->addElement(new XoopsFormHidden('id', $field->getVar('field_id'))); } 也就是讓所有「編輯既有欄位」的表單,都固定送出 hidden id。 修正後,送出欄位設定時,field.php 就能正常收到 POST id,不會再誤判成新增欄位,也不會產生空欄位名稱的 SQL。 修正後結果 經實測: - profile 欄位可正常編輯 - 欄位設定可正常儲存 - 不再出現 field_name ...

XOOPS 2.7 升級筆記:Smarty 4 不支援 <{php}> 的解決方法

 XOOPS 2.7 全面升級到 Smarty 4 後,舊佈景或舊模組最容易炸掉的地方,就是樣板裡的 `<{php}>...<{/php}>`。 原因很單純:Smarty 4 已經不支援在樣板中直接執行 PHP。也就是說,舊寫法如果還把 PHP 邏輯塞在 `.tpl` 裡,升級後就會出現 unknown tag、白畫面或 SmartyCompilerException。 目前比較穩的解法,不是去 hack Smarty,也不是讓 Smarty 重新開放任意 PHP,而是把原本散落在樣板中的 PHP 程式碼收回 PHP 檔案,整理成 function,再用 `$tpl->registerPlugin()` 註冊成 Smarty 標籤,最後在樣板中用新標籤取代原本的 `<{php}>`。 簡單說: 舊寫法: .tpl 直接寫 <{php}> PHP CODE <{/php}> 新寫法: PHP 檔建立 function → registerPlugin 註冊成 Smarty function → .tpl 改用 <{php_channel}> 這樣效果接近原本 `<{php}>`,但執行入口變乾淨,也比較符合 Smarty 4 的規則。 修改方法如下說明: 一、建立相容函式檔 建議先建立一個 PHP 檔,專門收納原本樣板裡的流浪 PHP,例如: modules/模組ID/function/tpl_smarty_compat.php 示例: <?php //Smarty 4 樣板流浪 PHP 收容區 function register_smarty_compat($tpl=""){ if(empty($tpl) || !is_object($tpl)) return; if(!method_exists($tpl,'registerPlugin')) return; static $registered=array(); $tplid=function_exists('spl_object_id') ? spl_object_id($tpl) : spl_object_hash($tpl); if(!empty($regist...

Apache 網站存取與嵌入防護設定(敏感檔案、目錄瀏覽、iframe 防護)

話說時間過得真快,轉眼間又收到上半年度局端的伺服器「弱點管制表」通報,其中當然免不了那些PHP/Apache需要升級項目,但本次多了三個新弱點項目,做個紀錄日後就能SOP處理! 弱點名稱:備份檔案洩漏 弱點概述:It is possible to retrieve file backups from the remote web server. 弱點名稱:Web 伺服器的目錄/資料夾可被瀏覽 弱點概述:Some directories on the remote web server are browsable. 弱點名稱:Web 應用程式具有點擊劫持(ClickJacking)的弱點 弱點概述:The remote web server may fail to mitigate a class of web application vulnerabilities. 這三個弱點可以一次解決,只需要找到 HTTPS vhost,也就是 <IfModule mod_ssl.c> 裡的 <VirtualHost *:443>。 該檔案通常由 certbot 自動產生,檔案名稱多為:000-default-le-ssl.conf(通常位於 sites-available 資料夾中,並連結到 sites-enabled 啟用) sudo nano /etc/apache2/sites-available/000-default-le-ssl.conf 打開編輯 <IfModule mod_ssl.c> <VirtualHost *:443> 略........................ ServerAdmin webmaster@localhost DocumentRoot /var/www/html #防護設定加在DocumentRoot 後面 #這段解決Web 伺服器的目錄/資料夾可被瀏覽問題 <Directory /var/www/html> Options -Indexes AllowOverride All Require all granted </Directory> #這段解決備份檔案洩漏 <FilesMatch "(?i)(~$|\.bak$|\.old$|\.or...

用CSS的@font-face自訂網站字體的方法

由於原本Google提供的@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+TC:wght@400&display=swap'); 會有阻塞渲染問題,導致 CSS 檔案載入變慢,瀏覽器必須先下載完 CSS,再解析到 @import,再去下載字體,這會增加網頁出現「空白字體(FOIT)」的時間。 基於效能優化,2026年建議改用CSS的@font-face自訂字體方法,也就是把字體放在自己的伺服器讓用戶載入網站字形,效能比@import方法要好,穩定性也更高,以下是完整建立@font-face方法說明。 1、先去fonts Google選擇需要的開源字體並下載 https://fonts.google.com/ 2、下載回來後解壓縮字形檔,因該是.ttf格式,建議改成 woff2格式會「比較穩」 .woff2 是現代瀏覽器標準壓縮過(小很多)Google Fonts 主力格式,以下網站可以更改字形副檔名格式 https://cloudconvert.com/ 點選Select File再選擇From my computer 選擇電腦中要改檔案的.ttf上傳後,選擇改為 woff2 Convert後等轉換完成,將.woff2 下載回來 3、在自己網站根目錄建一個fonts資料夾,然後吧字形檔貼入(例如cwTeXHei.woff2),接者再fonts資料夾中建一個.htaccess 貼上以下防熱連設定,避免字形資源被人拿去白漂 RewriteEngine On # 只處理字型檔 RewriteCond %{REQUEST_URI} \.(woff2|woff|ttf|otf)$ [NC] # 空 referer 放行:直接開檔、本地測試、某些瀏覽器情境 RewriteCond expr "%{HTTP_REFERER} == ''" RewriteRule .* - [L] # localhost / 127.0.0.1 放行:只在目前主機就是本地端時成立 RewriteCond %{REQUEST_URI} \.(woff2|woff|ttf|otf)$ [NC] RewriteCond %{HTTP_HOST} ^(localhos...

做一個簡單CK編輯器符合無障礙AA的設定方法!!

由於無障礙AA中規定對於A元素,或是iframe都需要有title語意說明,若是LINK外連還需要加上另開新視窗說明,如果用CK編輯器複製貼上,來源端就帶有連結但USER又沒設title就會被列為缺失,假使只是用於小型的說明用途欄位,用以下的CK設定參數就可以解決了! CKEDITOR.replace(" t extarea的id ", { height: 200, //高度 //toolbar參數,簡單的basicstyles及paragraph兩個插件(可自行增加) toolbar: [ { name: 'basicstyles', items: [ 'Bold', 'Italic', '-', 'RemoveFormat' ] }, { name: 'paragraph', items: [ 'NumberedList', 'BulletedList' ] } ], removePlugins: 'link,iframe,flash,forms', forcePasteAsPlainText: true }); 重點說明 removePlugins: 'link,iframe,flash,forms', 直接禁止:link,iframe,flash,forms類型的物件存在編輯器 forcePasteAsPlainText: true 貼上時,只保留純文字,不要任何格式 例如複製這一段有帶超連結的內容 貼到CK編輯框後,自動變成純文字格式,USER貼文也就不會有無障礙缺失的問題 這方法適合只需要簡單文字的編輯框,像是簡易討論區或是留言板,以及公開資料說明等,再必須符合無障礙AA規範下,用這方法能解決。 以上工作心得撰寫,有需要的朋友參考看看💁💁 工作心得撰寫: 徐嘉裕 Neil hsu

修正Xoops2.5.11佈景樣板system_search.tpl「顯示全部結果查」查詢失效的方法

今天無意中使用xoops的搜尋功能,結果發現資料多於預設數量時會被隱藏,但點選「顯示全部結果」卻查沒有半筆資料!!先釐清是不是佈景吃掉了showall變數,經確認換回官方的xswatch4佈景也是一樣結果,只能動手來找bug了,當然最先懷疑的一定是search.php,經過徹底查詢一路追到 case 'showall': //略.............. $xoopsTpl->appendByRef('results_arr', $results_arr); var_dump($results_arr);exit; //輸出陣列 確認$results_arr整包是有被輸出的,但樣板端卻沒顯示,這樣問題就很清楚了,是樣板端吃掉了$results_arr,接下來就來查樣板 ../themes/您的佈景id/modules/system/system_search.tpl (如果沒有去xswatch4整包拆回來) 發現$results_arr迴圈根本沒被輸出 <{foreach item=data from=$results_arr|default:null}> 略............ <{/if}> 這下傷腦筋了,PHP有給值,但到樣板卻消失,還好最後在前段找到這個兇手 <{if isset($nomatch) && $nomatch == true}> 因該是case 'showall':沒有給$nomatch = true 所以這一段才會無效,但如果改php檔之後升級xoops又會被覆蓋掉,那只能由樣板端處理 用筆記本開system_search.tpl,搜尋 <{if isset($nomatch) && $nomatch == true}> 替換成  <{if !empty($results_arr) || (isset($nomatch) && $nomatch != true)}> 這樣就能讓「顯示全部結果」恢復正常了(如下圖) 測試連結: https://neodw.com/search.php?query=%E7%B6%B2%E7%AB%99%E8%A8%AD%E8%A8%88&m...

Xoops免費佈景:neilambilight3.6正式版釋出-可兼容TAD模組,佈景設計開發:徐嘉裕Neil hsu

歷經一年多持續開發與優化,neilambilight 3.6 正式版正式登場。本次改版不僅全面強化無障礙AA支援,更導入尼爾自研的「Neil_ISP v2.0 分散式爬蟲攻擊智能防禦安全套件」,大幅提升網站整體安全與流量防護能力。 同時針對介面設計與操作體驗進行全面升級,加入aa-flow 自流動排版機制,可隨瀏覽器縮放自動調整版面,最高支援至400%,並達成TAD模組全面兼容,兼顧美觀、實用、安全、相容與無障礙等多重需求。 本次改版可說是一次從核心到體驗的全面進化,歡迎下載體驗全新升級的 neilambilight! 下載neilambilight3.6正式版       neilambilight3.6佈景展示站 新增與調整重點 無障礙 AA 全面升級 支援 NVDA 讀報、鍵盤操作優化、焦點管理強化 aa-flow 自流動版面(100%~400% 自適應) AWD 自適應流動排版系統 200% 自動單欄重排 250% / 300% / 400% 完整流動支援 全站 CSS REM 化 Neil_ISP v2.0 安全防護系統 蜜罐誘捕爬蟲 行為判斷封鎖 流量防護與 LOG 管理整合 TAD 模組全面兼容 自動補齊 JS / CSS 依賴 修正 tpl 衝突 Neil / TAD 智能分流機制 介面與操作體驗優化 新版 UI 設計(符合現代與 AA 安全色) 漢堡選單 / 浮動選單優化 字級切換與操作回饋強化 實用功能強化 短網址生成與還原功能 JSON-LD 結構化資料(SEO 強化) 表單與登入流程無障礙優化 GTM、AJAX、安全驗證補強     無論是視覺呈現、操作流暢度,或無障礙設計,neilambilight 3.6 都帶來全面性的升級體驗。 如果您正在使用 XOOPS 2.5.11 正式版,誠摯邀請您下載安裝,親自感受新一代佈景系統所帶來的穩定性與效率提升。 neilambilight3.6更新項目 修正無障礙NVDA讀報系統無法辨識JS的Enter事件,導...

使用Xoops的preload機制做fsockopen非同步幕後執行不占用前端資源

其實會想用 fsockopen 做非同步幕後執行,主要是因為客戶要開發自動批次下載Google雲端硬碟及自動建立檔案功能,如果用以往的活人撞針方法,觸發執行的那個ip會因為自動執行畫面整個延遲卡死(UX死當),必須改用非同步方式來解決 (瀏覽跟執行層分開) ,經過測試fsockopen確實能開一個新的HTTP請求至目標腳本然後斷線不理 (非同步) ,腳本自動以Web Server中獨立request執行程序,完全不影響前端頁面瀏覽不延遲,能優化UX體驗,不需要用活人獻祭了(改幕後執行),以下是框架及心得分享 要建立fsockopen前需要先使用Xoops的preload機制,preload是XOOPS提供的全域事件機制,可在每次request的特定生命週期節點(如 footer)插入自訂邏輯,使所有頁面都能觸發指定行為,換句話說在模組中執行preload的腳本,Xoops全體頁面都能被觸發事件(全域事件機制),所以拿來當作fsockopen的執行footer非常適合。 preload = XOOPS 全域事件鉤子(Hook) XOOPS 啟動流程中 → 每個 request 都會觸發 preload → 依事件執行(你用的是 Footer) 建立preload方法 先在xoops模組根目錄建立一個preloads,在置入一個core.php檔案 例如:my_modules/preloads/core.php 然後加入以下代碼 <?php class NeilalbumCorePreload extends XoopsPreloadItem { public static function eventCoreFooterStart($args) { //eventCoreFooterStart 所有頁面 / 在輸出footer前 /都會觸發 async_trigger(); } } function async_trigger() { global $xoopsModuleConfig,$xoopsModule,$isAdmin; //做一個$token $secret_id="rEDBzCyHEJ7Yv32ie5JPyB0WmKP9caeDPbkpfc1L"; //可改成自己要的雜奏碼 $ts = time(); $tok...

好用的Chrome瀏覽器批次下載套件DownThemAll!推薦-終於不用一個一個下載了!!

建置網站最怕遇到的就是舊資料移轉,有時候檔案數量龐大,一個一個下載手都酸了,經查詢發現有更好的方法能決這問題,這裡將經驗分享給大家!! 例如這一個頁面,有60幾個PDF檔要下載,一個一個下載完天都亮了!!這時候真的需要借用工具的力量來幫我們自動化處理!! 推薦一個好用的Chrome瀏覽器批次下載套件DownThemAll! 先點Chrome瀏覽器最右上方的三個橫點,打開選單,找到「擴充功能」再選擇子選單「前往Chrome應用程式商店」 然後輸入關鍵字「DownThemAll」找到套件後安裝起來,接下來前往要下載檔案的頁面,點選右上方的工具列,找到DownThemAll,點選打開! 選擇DownThemAll打開設定選單,選擇DownThemAll,透過篩選器選擇設定 完成後按下載,只需要enter到底就能下載完成,檔案預設會放在C:\XXXX\XXXXX\Downloads\downthemall 目錄中 或是選擇OneClick也能下載, 一樣只需要鍵盤enter一直按到叮咚一聲,檔按下載就完成,至於為什麼要用OneClick,主要是他能模擬人工點擊,如果用批次,若是檔案中又包有iframe就會被下載兩次,或是更多次,因此OneClick是個不錯的決方法,經實測頁面60個pdf檔批次下載回來也是60個,數量正確檔按無缺損,這套件確實能解決大量檔案下載問題,有需要的朋友可以參考看看!! 備註:OneClick 模式並非解析整頁資源,而是僅擷取使用者可見之下載連結,等同模擬人工點擊流程,因此可避免因 iframe 或預覽機制造成的重複下載問題。 工作心得撰寫: 徐嘉裕 Neil hsu

Ubuntu 私有雲 PPA 安裝失敗/版本不上升解法(回應timeout)

今天在 Ubuntu 私有雲環境安裝 PPA 套件時遇到奇怪現象: 安裝apache2 sudo add-apt-repository -y ppa:ondrej/apache2 返回110 timeout 安裝php sudo add-apt-repository -y ppa:ondrej/php 返回110 timeout 我在想是不是卡到陰了!!經過查詢原來是add-apt-repository壅塞被卡住了,才會返回timeout,解決方法就: 手動加入 PPA + 手動匯入 GPG key, 完全不經過 add-apt-repository,就不會 timeout。 方法如下: 1、先取得目前 Ubuntu codename(jammy / noble / focal...) . /etc/os-release echo $VERSION_CODENAME 2、加入Apache2 PPA echo "deb http://ppa.launchpad.net/ondrej/apache2/ubuntu $VERSION_CODENAME main" \  | sudo tee /etc/apt/sources.list.d/ondrej-apache2.list 3、加入PHP PPA  echo "deb http://ppa.launchpad.net/ondrej/php/ubuntu $VERSION_CODENAME main" \  | sudo tee /etc/apt/sources.list.d/ondrej-php.list 4、匯入 PPA key(使用 port 80 避開防火牆)apt-key 已被標記為 deprecated,但目前仍可正常使用。 sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E5267A6C 5、更新套件庫並確認 Apache Candidate 版本 sudo apt update apt-cache policy apache2 需要返回這樣版號(不能兩個一樣) Installed: 2.4.52-xxx Candidate: 2.4.66-xxx   ← 必須比 I...

用 Linux 的 ipset 建立大量黑名單替換 Apache 的 .htaccess 黑名單方法

雲主機建好 LAMP 之後,接下來最重要的是建立 L3 及 L4 防火牆規則,把一些爬蟲、代理池與高風險國家 IP 區段封鎖,減輕硬碟的 I/O 壓力。 不然每隔幾秒就來一次請求,就算 L7 應用層有高階防爬蟲機制,還是會消耗雲主機的算力。 當然最好是在路由端用硬體防火牆清洗,但因為是雲主機沒有實體路由,因此改用 Linux kernel 層級的黑名單系統 ipset 也能達到 L3 與 L4 清洗效果,讓 Apache/PHP 完全碰不到,不吃 CPU、不吃 I/O。 經過實際執行、爆肝測試後,去除所有失敗方法,以下為正確建立ipset 黑名單的方法: 1、建立 ipset sudo ipset create blacklist hash:ip 如果看到: ipset v7.x.x: Set cannot be created: already exists 代表曾經建立過,需要 destroy。 如果返回: Command 'ipset' not found, but can be installed with: apt install ipset 表示 Linux 初始環境沒有預裝 ipset,輸入以下指令安裝: sudo apt update sudo apt install ipset -y 完成後驗證: ipset list 如果返回: ipset v7.x.x: The set with the given name does not exist 表示 ipset 已成功安裝(但還沒建立 blacklist)。 2、建立一份「只有網段」的列表檔 輸入指令建立 sudo nano /root/blacklist.txt 貼上以下內容(改成您自己的IP名單) 1.0.1.0/24 1.0.2.0/23 1.0.8.0/21 1.0.32.0/19 (略…) Ctrl+O 儲存 → Enter 確認 → Ctrl+X 返回。注意:一定要用 nano 建立,避免 BOM/CRLF 問題。 3、建立自動載入腳本 輸入指令建立 sudo nano /usr/local/bin/ipset-load.sh 貼入以下腳本 #!/bin/bash # 建立 blacklist(若存在就忽略) ipset create blacklist hash:net...

雲主機設定 VirtualHost 方法(將 www 與 IP 自動 301 轉向單一網址)— SEO 最佳化

完成雲主機 LAMP 架設後,下一步就是將 DNS 指向新空間。 www.website.com 可以進入網站 website.com 也能進入網站 伺服器 IP 也能直接打開網站 等於一個網站有多個入口。 這會造成: 搜尋引擎收錄混亂(www / non-www / IP 多份內容) SEO 分數被分散 資料表網址寫入不一致(不同格式混用) 因此,我們需要透過 VirtualHost 與 301 Redirect,將所有入口統一導向單一正式網址(Canonical Domain)。 一、建立 HTTP VirtualHost(入口收斂) sudo nano /etc/apache2/sites-available/default_host.conf <VirtualHost *:80> ServerName website.com ServerAlias www.website.com + 你的IP例如:123.123.12.33 RewriteEngine On RewriteRule ^ https://website.com%{REQUEST_URI} [L,R=301] </VirtualHost> 請將 website.com 改為自己的網域。 正確流程 (重要) 先建立VirtualHost:80 ↓ 完成網站建置 ↓ 申請SSL(自建443) ↓ 再來做VirtualHost:443 二、SSL(HTTPS 443)設定 (通常由 certbot 自動產生) (需要先建立SSL後再處理443的 設定 )(沒有SSL根本不存在443問題) <IfModule mod_ssl.c> <VirtualHost *:443> ServerName website.com ServerAlias www.website.com DocumentRoot /var/www/html <Directory /var/www/html> AllowOverride All Require all granted </Directory> ...

使用雲主機Xoops資料夾權限設定方法(安全)

由於早期網站大多租用虛擬主機,主機商(虛擬主機)不開放 owner 權限設定。FTP 上傳的檔案都是你自己的 user,但 Apache 執行的身分是 www-data(或 nobody)。因此 Apache 無法寫入 FTP 上傳的目錄。能讓 PHP 寫入資料的唯一方法,就是把資料夾權限設為 777(完全開放) 。 但現在已經 2025 年,這個方法在現代 雲主機 = 直接開大門請人入侵、請人來挖礦 。 只要輸入像下面這種命令: curl -T shell.php http://website.com.tw/uploads/ 把一句話木馬丟進去。或者: curl -X PUT -d "<xml>亂碼" http://website.com.tw/uploads/ 整個 uploads 直接被毀。 好在時代進步,多數虛擬主機資料夾,只要設成 755 就能讓 PHP 正常存取(因為 suPHP 或 CageFS) 。至於雲主機或 VPS,則應該使用以下方法取代 777: 設定資料夾權限(替代777方法) chmod -R 775 /var/www/html/uploads chown -R www-data:www-data /var/www/html/uploads 設定檔案權限(替代777方法) chown www-data:www-data /var/www/html/xsitemap.xml chmod 664 /var/www/html/xsitemap.xml 這是 XOOPS 上雲後最安全 & 最正確的權限組合。 Apache 能寫、你能寫、非權限者不能寫 → 完美安全模型。 XOOPS 正確安全權限(建議清單) 目錄   權限  owner uploads   775  www-data xoops_data/caches   770  www-data xoops_data/configs   770   www-data xoops_data/data   770  www-data xoops_data/protector      770  www-data xoops_l...

Ubuntu主機ssh指定固定ip連線方法(防止掃描及暴力破解)

除非是內網段私有雲,不然一般 VPS 或雲主機的預設模式 ssh 是完全開放的,Port 22 對 0.0.0.0/0 全世界開放,只要知道 IP + 密碼即可登入,如果不是使用金鑰方式連線,非常建議建立 UFW 防火牆規則,將 SSH 登入限制為固定 IP 白名單,否則 SSH 端口可能每分鐘被測試 50~100 次。 這些都是正常的掃描行為: Failed password for root from 152.xx.xx.xx Failed password for root from 103.xx.xx.xx Invalid user ubuntu from 185.xx.xx.xx LOG 膨脹事小,如果密碼真的被猜出來,整台雲主機等於送給駭客當挖礦機玩具。 因此必須建立 SSH 白名單,方法如下: 步驟 1:安裝 UFW 防火牆(Ubuntu 標準 L4 防護) apt update apt install ufw -y 備註:如果只需要基本防護不綁死IP輸入以下指令即可 ufw allow 22 ufw allow 80 ufw allow 443 然後直接跳到步驟六(完成後確認一下ufw status)沒問題就結束 步驟 2:只允許你家 / 公司電腦的固定 IP 連線 SSH ( 紅色部分請改為您的固定 IP) ufw allow from 125.227.xxx.xxx to any port 22 步驟 3:封鎖全世界的 SSH(IPv4/IPv6 全封) ufw deny 22/tcp ufw deny 22 步驟 4:開放網站必要 Port ufw allow 80 ufw allow 443 步驟 5:檢查是否存在錯誤規則(如有 → 必刪) ufw status numbered 若有出現以下規則必須刪除,否則 SSH 白名單無效: 1、全世界允許 SSH(危險) [ 1] 22/tcp ALLOW IN Anywhere 刪除 → ufw delete 1 2、IPv6 全世界允許 SSH [ 6] 22/tcp (v6) ALLOW IN Anywhere (v6) 刪除 → ufw delete 6 步驟 6:啟動防火牆(開始生效) ufw enable 提示: Command may disrupt existing ssh conn...

升級Ubuntu22.04(Apache / PHP ) Ondřej Surý 的 PPA套件方法

當初使用 Ondřej Surý 的 PPA套件安裝(Apache / PHP )就是為了解決惱人的資安通報,果然網站上線沒多久通報就來了,這次主要有兩項要升級(Apache要高於2.4.64 / PHP要高於8.3.23),剛好來試看看傳說中的 PPA套件升級到底有多容易,以下是升級完整步驟紀錄 先備份檔案以防萬一(後續比對用)重要 sudo mkdir -p /root/apache_backup_$(date +%Y%m%d) sudo cp /etc/php/8.3/apache2/php.ini /root/apache_backup_$(date +%Y%m%d)/ sudo cp /etc/apache2/sites-available/default-ssl.conf /root/apache_backup_$(date +%Y%m%d)/ sudo cp /etc/apache2/mods-available/ssl.conf /root/apache_backup_$(date +%Y%m%d)/ sudo cp /etc/apache2/apache2.conf /root/apache_backup_$(date +%Y%m%d)/ sudo cp /etc/apache2/conf-available/security.conf /root/apache_backup_$(date +%Y%m%d)/ sudo cp /etc/apache2/ports.conf /root/apache_backup_$(date +%Y%m%d)/ 這樣所有重要設定就會備份到 /root/apache_backup_ 20251020 /,如果升級後有任何異常,你只要: sudo cp /root/apache_backup_ 20251020 /* /etc/apache2/... sudo systemctl reload apache2 就能一鍵復原 (紅字為今天日期) 再來升級Apache 1、更新套件列表:  sudo apt update 2、升級 Apache : sudo apt install --only-upgrade apache2 備註: 如果發生Progress: [ 82%] [##################...

Google行事曆設定和共用的方法,可以讓多人共同發佈事件在同一個月曆上!!(共同管理)

Google行事曆有一個功能就是可以【設定和共用】,讓多人共同發佈事件在同一個月曆上,共同管理,例如建立了一個主行事曆,然後要讓A,B,C能同時在這主行事曆上發佈事件(新增/編輯/刪除),方法很簡單的,首先,先要取得A,B,C的E-MAIL帳號 然後前往Google行事曆首頁,左下方的我的日曆,找到需要共同發佈事件的月曆,點選右邊的【行事曆選項】 會彈出視窗,選擇【設定和共用】 找到【共用對象】,下面有一個【新增使用者和群組】 點選後會彈出視窗,這裡輸入A,B,C的E-MAIL帳號(可連續操作),下面的權限選擇【進行變更並管理共同設定】(或是按需求自定) 完成後點選右下角的傳送,這樣A,B,C就會收到共用日曆的邀請,點選郵件中的【加入共用日曆】就可以在主日曆中發佈事件 最後是A,B,C如果要將事件發佈在主日曆,建立事件時,左邊有一個行事曆的ICON及下拉選單,選單要選取主日曆的名稱,不然事件會發在自己的日曆上,主日曆不會顯示。 為了避免日後又忘記操作步驟,寫成工作紀錄保存,順便分享給有需要的朋友參考! 工作心得撰寫: 徐嘉裕 Neil hsu

用CSS做出來一個文字漸層+文字白框+文字陰影的LOGO區塊,CSS最終解法並符合無障礙

網站符合無障礙已經是當今的趨勢了,所以在設計LOGO動畫上不能再用傳統的canvas動畫,因為圖片沒版法自流動,無法符合無障礙AA的CRTL+200放大版面流動效果,只能全部改為CSS+純文字,問題不是在動畫,而是如何用CSS至少能做出70%能像PSD圖檔那樣的文字效果,美觀也是要兼顧,經過努力研究與資料參考,終於寫出來這個【文字漸層+文字白框+文字陰影】CSS效果,如下圖: 以下就是整個代碼結構 透過F12撈出來的HTML結構 <div id="logoimgbox2" aria-label="桃園市立富岡國民中學" > <span aria-hidden="true" tabindex="-1" class="logo_01" data-storke="桃園市立" >桃園市立</span> 略.......................... </div> 說明 aria-label是給讀報軟體用的讀報資訊 aria-hidden="true" tabindex="-1" 是讓讀報軟體不要讀取容器中的文字,因為用了 ::before建構一個文字在底層,同樣文字被讀報兩次會被列缺失 data-storke是給CSS ::before的: attr(data-storke);用的 以下為CSS代碼 #logoimgbox2 {     position: absolute;     top: 44px;     left: 174px;     color: #181818;     font-size: 290%;     word-break: break-all;     font-family: Noto Sans TC;     font-weight: 600;     filter: drop-shadow(1px 1px 3px rgba(0, 0, 0, .5));  // 文字陰影(黑色)     letter-spacing: 0.6rem; } #logoimgbox2 .logo_...

如Let's Encrypt的 SSL憑證被防火牆GeoIP封鎖無法更新(HTTP-01),可改用 DNS‑01方法進行更新

有些學校伺服器因為長期遭到網路爬蟲攻擊洗流量,乾脆由上層路由防火牆GeoIP鎖掉台灣以外的IP,這樣是能立刻減少流量及0/1消耗,因為國外的爬蟲都被擋掉了,但同樣副作用也導致Let's Encrypt的 SSL憑證更新失敗,因為國外的IP都被鎖了,測試方式很簡單,只要於下列網址輸入需要模擬Let's Encrypt更新的網站,即可測試 Let's Debug: https://letsdebug.net/ 如果返回 紅字 ,那就是IP被鎖,上層 GeoIP 限制會讓驗證節點直接超時(Timeout during connect),連80port都連不到, 綠字 表示沒問題, 黃字 雖有問題仍可更新 解決無法更新方案就只能改用DNS‑01驗證,方法如下: 步驟 1:進入伺服器並執行 Certbot (紅字改為您網址) sudo certbot certonly --manual --preferred-challenges dns -d example.com 步驟 2:Certbot 會顯示 TXT 記錄資訊 它會出現類似這樣的提示: Please deploy a DNS TXT record under the name: _acme-challenge.example.com. with the following value: s9pRq9l5R9Xg1wKQyEjQ0i_Z4Hh3V9cQeH6jLn2Qzj8 Before continuing, verify the TXT record has been deployed. 將以下綠字及紅字複製下來: 記錄名稱: _acme-challenge .example.com 記錄值: s9pRq9l5R9Xg1wKQyEjQ0i_Z4Hh3V9cQeH6jLn2Qzj8 備註:終端機上只需要把滑鼠左鍵長壓拖曳後放開即可自動複製,不需要用鍵盤的CTRL+C 步驟 3:在 Infoblox或是網址管理介面新增 TXT 記錄 登入 Infoblox 或網址管理介面(外網段) 找到 網址 對應的 DNS Zone 新增 TXT 記錄: Name: _acme-challenge (Infoblox 會自動加上 .example.com,不需要自己寫完整) Text / Value: s9...