Compare commits
17 Commits
leokhoa-pa
...
7.0.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6959b13189 | ||
|
|
2631fda37b | ||
|
|
3fcd32d767 | ||
|
|
b371252f27 | ||
|
|
18992b2d5c | ||
|
|
5cf5f6b2ae | ||
|
|
45d2c3f117 | ||
|
|
f58e47d630 | ||
|
|
b23f970bea | ||
|
|
f9f71aa06b | ||
|
|
93a49297b6 | ||
|
|
97b9cff42a | ||
|
|
d62e7dd284 | ||
|
|
4aea889be0 | ||
|
|
23a6c4161a | ||
|
|
b999e0eff8 | ||
|
|
db99be8e41 |
13
SECURITY.md
Normal file
13
SECURITY.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
| Version | Supported |Reason |
|
||||
| ------- | ------------------ | ---------- |
|
||||
| >=7.0 | :white_check_mark: | |
|
||||
| <=6.0 | :x: | EOL |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
If you find a security vulnerability in Laragon, please report it via email to Leo Khoa at leo@laragon.org
|
||||
We take security seriously, and all reports will be promptly addressed.
|
||||
@@ -250,14 +250,14 @@ date: 20181016
|
||||
|
||||
# Setup
|
||||
900 = يعمل لاراقون بشكل سريع جداً ولديه مساحة ذاكرة منخفضة جداً ( <4 ميجابايت)
|
||||
901 = سيحصل تطبيقك على رابط لطيف ---> http://app.test
|
||||
901 = سيحصل تطبيقك على رابط لطيف ---> https://app.test
|
||||
902 = أضف محرر النص و موجه الأوامر إلى قائمة النقر بزر الفأرة الأيمن
|
||||
903 = طرق سريعة لفتح محرر النصوص وموجه الاوامر
|
||||
904 = عرض ملف اقرئني
|
||||
905 = تشغيل لاراقون
|
||||
|
||||
# SSL
|
||||
906 = إنشاء تلقائي لشهادات SSL
|
||||
906 = Auto-generated SSL Certificates
|
||||
|
||||
# Version 3
|
||||
140 = تجهيز البيانات...
|
||||
|
||||
@@ -250,7 +250,7 @@ date: 20192108
|
||||
|
||||
# Setup
|
||||
900 = Laragon runs extremely fast and has very low memory footprint (< 4 MB)
|
||||
901 = Sizin tətbiqiniz qısa yol əldə edəcək ---> http://app.test
|
||||
901 = Sizin tətbiqiniz qısa yol əldə edəcək ---> https://app.test
|
||||
902 = Sublime Text əlavə et && Terminal to the Right-Click Menu
|
||||
903 = Text editləyicini açmaq üçün sürətli yollar & Əmr lövhəsi
|
||||
904 = README faylına bax
|
||||
|
||||
@@ -252,7 +252,7 @@ date: 20161113
|
||||
|
||||
# Setup
|
||||
900 = Laragon работи изключително бързо и използв много малко от РАМ (< 4 MB)
|
||||
901 = Твоето приложение ще изполва "красиви" линкове ---> http://app.test
|
||||
901 = Твоето приложение ще изполва "красиви" линкове ---> https://app.test
|
||||
902 = Добави Sublime Text && Terminal в меню от десен клик
|
||||
903 = Лесен начин да стартиране Текстов редактор & Команден прозорец
|
||||
904 = Покажи README файла
|
||||
|
||||
@@ -253,7 +253,7 @@ date: 20190827
|
||||
|
||||
# Setup
|
||||
900=Laragon运行得非常快,具有非常低的内存占用(小于4 MB)
|
||||
901=你的“项目”将得到优雅链接 ---> http://项目.test
|
||||
901=你的“项目”将得到优雅链接 ---> https://项目.test
|
||||
902=添加 Sublime Text 和 Terminal 到右击菜单
|
||||
903=快速打开 文本编辑器 和 命令行
|
||||
904=查看README文件
|
||||
|
||||
@@ -1,292 +1,257 @@
|
||||
--------------------------------------------------------
|
||||
author: SiderealArt - admin at siderealart.me - https://siderealart.me/
|
||||
date: 20220125
|
||||
author: Kyomini - Kyomini@qq.com - https://laragon.com.cn
|
||||
date: 20160802
|
||||
Language: Traditional Chinese
|
||||
--------------------------------------------------------
|
||||
#主界面
|
||||
100=全部啟動
|
||||
100=啟動所有
|
||||
101=網站
|
||||
102=資料庫
|
||||
103=終端機
|
||||
102=數據庫
|
||||
103=終端
|
||||
104=根目錄
|
||||
105=停止
|
||||
106=正在停止...
|
||||
107=重新載入
|
||||
106=停止中...
|
||||
107=重新加載
|
||||
108=啟動
|
||||
109=版本
|
||||
110=已啟用
|
||||
111=全部停止
|
||||
111=停止所有
|
||||
112=關閉
|
||||
113=最小化
|
||||
114=最大化
|
||||
115=是
|
||||
116=否
|
||||
117=取消
|
||||
118=OK
|
||||
118=好的
|
||||
119=開
|
||||
120=關
|
||||
121=選單
|
||||
122=如有任何問題,歡迎聯絡我們
|
||||
121=菜單
|
||||
122=如有任何問題,請隨時聯系!
|
||||
|
||||
# Menu
|
||||
199=www
|
||||
200=工具
|
||||
201=PATH 環境變數
|
||||
202=傳輸檔案
|
||||
203=建立專案
|
||||
204=切換專案
|
||||
205=建立資料庫
|
||||
206=更換 root 密碼
|
||||
201=PATH 環境變量
|
||||
202=傳輸文件
|
||||
203=創建項目
|
||||
204=切換項目
|
||||
205=創建數據庫
|
||||
206=更換root密碼
|
||||
207=郵件接收
|
||||
208=查看最新郵件
|
||||
209=打開郵件路徑
|
||||
210=取得 sendmail_path
|
||||
211=設定
|
||||
212=郵件傳送
|
||||
213=擴充功能
|
||||
209=打開郵箱路徑
|
||||
210=獲取 sendmail_path
|
||||
211=配置
|
||||
212=郵件發送
|
||||
213=擴展
|
||||
214=網站後臺
|
||||
215=登入
|
||||
216=設定
|
||||
215=登陸
|
||||
216=參數
|
||||
217=退出
|
||||
218=專案名稱
|
||||
218=項目名稱
|
||||
|
||||
|
||||
# 首選項
|
||||
300=一般
|
||||
301=服務 && 連接埠
|
||||
310=讓 Laragon 隨 Windows 啟動
|
||||
311=讓 Laragon 隨 Windows 自動啟動
|
||||
312=啟動後最小化
|
||||
300=常規
|
||||
301=服務 && 端口
|
||||
310=Windows系統啟動時運行Laragon
|
||||
311=Windows系統啟動時自動運行Laragon
|
||||
312=最小化運行
|
||||
|
||||
# \n for a new line
|
||||
313=將 Laragon 最小化到系統匣。\n左鍵點擊系統匣的 Laragon 圖示來開啟 Laragon
|
||||
313=Laragon最小化到系統托盤\n左擊系統托盤Laragon圖標顯示Laragon
|
||||
314=自動啟動所有服務
|
||||
315=當 Laragon 運行時自動啟動所有選擇的服務
|
||||
315=當Laragon運行時自動啟動所有選擇的服務
|
||||
316=語言
|
||||
|
||||
317=檔案根目錄
|
||||
318=點擊以更換檔案根目錄
|
||||
319=資料路徑
|
||||
320=點擊以更換 MySQL 資料路徑
|
||||
317=文件根目錄
|
||||
318=點擊更換文件根目錄
|
||||
319=數據路徑
|
||||
320=點擊更換MySQL數據路徑
|
||||
|
||||
322=自動建立虛擬主機
|
||||
323=只需放置資料夾到檔案根目錄 & 重新載入 Apache,Laragon 將自動建立對應的主機名稱到 hosts 檔案和Apache 的虛擬主機
|
||||
322=自動創建虛擬主機
|
||||
323=只需放置文件夾到文件根目錄 &重載Apache,Laragon將自動創建對應的主機名到hosts文件和Apache虛擬主機
|
||||
|
||||
# %s for a string placeholder
|
||||
324=主機名稱格式
|
||||
325=主機名格式.\n例如: 如果您的專案名是 %s
|
||||
324=主機名
|
||||
325=主機名格式.\n例如: 如果妳的項目名是 %s
|
||||
|
||||
|
||||
328=進階
|
||||
329=當呼叫 mail() 函數時,Laragon 將在畫面右下角\n顯示郵件資訊。
|
||||
330=視窗將顯示
|
||||
331=此功能將幫助您快速瀏覽郵件內容。\n您也可以透過:\n選單 > PHP > MailCatcher 來檢視最新郵件的內容
|
||||
328=高級項
|
||||
329=當調用 mail() 函數,Laragon將顯示生成的郵件信息\n在妳屏幕右下角的小窗口裏
|
||||
330=窗口將顯示
|
||||
331=此特性將幫助妳快速瀏覽郵件內容.\n妳也可以任何時候瀏覽最新郵件:\n菜單 > PHP > 郵件接收
|
||||
|
||||
340=Gmail 帳號
|
||||
340=Gmail 地址
|
||||
341=Gmail 密碼
|
||||
342=測試傳送郵件
|
||||
343=您可能需要在您的 Google 帳號中允許 「低安全性應用程式存取」。\n您的 Gmail 密碼將被加密。\n啟用後,您可以輸入此行指令來輕鬆的傳送電子郵件:
|
||||
342=測試發送郵件
|
||||
343=妳看到的Gmail密碼將被加密\n當啟用後,妳可以通過互聯網輕松發送郵件,只需壹行:
|
||||
|
||||
|
||||
# 郵件分析儀
|
||||
350=郵件分析
|
||||
351=傳送測試郵件到
|
||||
351=發送測試郵件到
|
||||
352=重新測試
|
||||
353=重新測試發送郵件,您可以輸入其他電子郵件地址來測試。
|
||||
353=重新測試發送郵件,妳可以輸入另外的郵箱地址來測試。
|
||||
354=關閉
|
||||
|
||||
|
||||
# 系統托盤
|
||||
400=Laragon 已最小化
|
||||
401=已切換至專案:
|
||||
402=已建立資料庫!
|
||||
403=更改 MySQL 資料庫 root 密碼成功!
|
||||
404=Apache 已重新載入!
|
||||
405=路徑錯誤!
|
||||
406=偵測到新專案!\nLaragon 將呼叫 Node.js 來幫您建立虛擬主機!
|
||||
400=Laragon已最小化
|
||||
401=切換項目:
|
||||
402=已創建數據庫!
|
||||
403=更改MySQL數據庫root密碼成功!
|
||||
404=Apache 已重新加載!
|
||||
405=錯誤路徑!
|
||||
406=偵測到新項目!\nLaragon 將調用NodeJs來為妳創建虛擬主機!
|
||||
|
||||
|
||||
# 提示
|
||||
500=線上幫助
|
||||
501=左鍵點擊:Laragon - 右鍵點擊:選單
|
||||
500=在線幫助
|
||||
501=左鍵單擊: Laragon - 右鍵單擊: 菜單
|
||||
502=開始頁面
|
||||
503=資料庫管理
|
||||
504=打開命令提示字元 (快捷鍵: CTRL+ALT+T)
|
||||
505=Laragon 將會呼叫 Node.js 來建立虛擬主機\n若您不想要使用 Node.js,\n請以管理員身分執行 Laragon
|
||||
506=檔案根目錄
|
||||
503=數據庫管理
|
||||
504=打開命令提示 (快捷鍵: CTRL+ALT+T)
|
||||
505=Laragon將會調用Nodejs來創建虛擬主機 \n如果妳想要這個功能無需調用Nodejs \n作為Administrator運行Laragon
|
||||
506=文檔根目錄
|
||||
|
||||
# Quick create website/project
|
||||
600=正在建立
|
||||
601=已建立
|
||||
602=正在下載
|
||||
603=已完成下載
|
||||
604=正在解壓縮
|
||||
605=已完成解壓縮
|
||||
606=產生美化連結
|
||||
607=快速建立
|
||||
600=創建中
|
||||
601=已創建
|
||||
602=下載中
|
||||
603=已下載
|
||||
604=提取中
|
||||
605=已提取
|
||||
606=生成優雅鏈接
|
||||
607=快速創建
|
||||
608=網站名稱
|
||||
609=請指定專案名稱!
|
||||
610=已建立 %s!
|
||||
611=無法建立 %s,原因:%s
|
||||
609=請指定項目名!
|
||||
610=%s 已創建!
|
||||
611=無法創建 %s ,原因如下: %s
|
||||
612=瀏覽
|
||||
613=點擊以前往專案資料夾
|
||||
614=點擊以瀏覽網站
|
||||
613=點擊前往項目文件夾
|
||||
614=點擊瀏覽網站
|
||||
|
||||
|
||||
|
||||
# Messages
|
||||
700=已複製 sendmail_path 到剪貼簿!
|
||||
701=此功能無法在您的電腦上使用!
|
||||
702=請先啟動 %s!
|
||||
700=sendmail_path已復制到粘貼板!
|
||||
701=此特性無法在您電腦上使用!
|
||||
702=請先啟動 %s
|
||||
703=名稱無效!
|
||||
704=此目錄未包含有效的 Laravel 專案!
|
||||
705=請啟動 PHP 服務!
|
||||
706=前往選單 > 設定 > 服務 & 連接埠,並啟動 PHP 服務
|
||||
707=專案已存在!
|
||||
708=如果您真的想要建立此專案,請先刪除專案資料夾並重試!
|
||||
709=無資料夾!
|
||||
710=無檔案!
|
||||
711=%s 未執行,請先啟動 Redis 伺服器!
|
||||
712=請不要在 Laragon 安裝路徑中使用空格 (為避免以後的麻煩)!
|
||||
713=%s 服務正在執行,但在其他處理程序下。
|
||||
714=請停止您目前的 WAMP 堆疊,否則 Laragon 將會出現未知錯誤
|
||||
715=處理程序路徑:
|
||||
704=此目錄未包含壹個有效的Laravel項目!
|
||||
705=請打開PHP服務!
|
||||
706=前往 菜單 > 參數 > 服務 & 端口,並啟用PHP服務
|
||||
707=項目已存在!
|
||||
708=如果妳真的希望創建這個項目,嘗試刪除此項目文件夾!
|
||||
709=無文件夾
|
||||
710=無文件
|
||||
711=%s 未運行,請先啟動Redis服務!
|
||||
712=請不要在Laragon安裝路徑中使用空格(為避免以後的麻煩)!
|
||||
713=%s 服務正在運行,但在其他進程
|
||||
714=請停止妳當前的WAMP堆棧否則Laragon將會出現未知錯誤
|
||||
715=進程路徑:
|
||||
|
||||
# Hope you never see this :)
|
||||
716=哦不!Laragon 偵測到例外狀況!
|
||||
717=無法建立資料庫 %s,原因:%s
|
||||
718=無法更改 MySQL root 密碼,原因:%s
|
||||
719=您必須提供有效的 Gmail 帳號!
|
||||
720=無法在啟動資料夾中建立捷徑!
|
||||
721=無法從啟動資料夾刪除捷徑!
|
||||
722=格式錯誤!必須含有專案名稱格式 {name}.xxx!
|
||||
723=格式錯誤!主機名稱無效!
|
||||
724=MySQL 資料路徑無效!
|
||||
725=您必須在選單 > 設定 > 服務 & 連接埠中啟用 Apache 及 MySQL 服務!
|
||||
716=哦!No!Laragon檢測到異常!
|
||||
717=無法創建數據庫 %s ,原因是: %s
|
||||
718=無法更改MySQL root密碼,原因是: %s
|
||||
719=妳必須指定壹個有效的Gmail地址
|
||||
720=無法在啟動目錄創建快捷方式!
|
||||
721=無法在啟動目錄中刪除快捷方式!
|
||||
722=錯誤的格式!必須要有壹個項目名稱模式在{name}.xxx!
|
||||
723=錯誤的格式!不是壹個有效的主機名!
|
||||
724=不是有效的MySQL數據路徑!
|
||||
725=妳必須啟用Apache 和 MySQL服務在 services in 菜單 > 參數 > 服務 & 端口!
|
||||
|
||||
# When Laragon can not modify hosts file
|
||||
726=哎呀!您的系統阻止更改 hosts 檔案。\n請檢查您的防毒軟體和安全性分頁中的權限,查看檔案是否為唯讀\ nLaragon 將暫時停用 「自動建立虛擬主機」 功能!
|
||||
727=為了使此功能生效,您可以試試:\n1 前往:%s\drivers\etc\n2。右鍵點擊 hosts 檔案並取消勾選唯讀核取方塊。
|
||||
728=提醒:hosts 檔案目前權限:
|
||||
726=哎呀!妳的系統阻止更改hosts文件\n請檢查妳的殺毒軟件或權限的安全選項卡或檢查的文件是否是只讀文件\ nLaragon將暫時停用“自動創建虛擬主機”功能!
|
||||
727=為了使這壹特征生效,妳可以試試:\n1 轉到: %s\drivers\etc\n2 右鍵單擊hosts文件並取消只讀復選框
|
||||
728=註意:當前hosts文件權限:
|
||||
|
||||
# hosts file is Read-only
|
||||
729=唯讀
|
||||
729=只讀
|
||||
|
||||
# Write permission in Security tab
|
||||
730=安全性 > 寫入
|
||||
730=安全 > 寫入
|
||||
|
||||
|
||||
# MySQL
|
||||
800=資料庫名稱
|
||||
|
||||
800=數據庫名稱
|
||||
801=新密碼
|
||||
802=舊密碼
|
||||
802=當前密碼
|
||||
|
||||
|
||||
|
||||
# Version 2
|
||||
219=Ngrok
|
||||
220=分享
|
||||
221=Ngrok 連結已複製到剪貼簿!
|
||||
222=Ngrok 通道已就緒!
|
||||
223=點擊以手動以管理員身分編輯 host 檔案。
|
||||
221=Ngrok鏈接已復制到粘貼板!
|
||||
222=Ngrok 通道已經準備好!
|
||||
223=作為管理員手動編輯hosts文件。
|
||||
224=已開始
|
||||
226=解壓縮中
|
||||
227=已解壓縮
|
||||
228=不支援此格式
|
||||
229=請耐心等待直到解壓縮完成
|
||||
230=連結錯誤
|
||||
231=下載時發生錯誤,請重試!
|
||||
232=發生錯誤!也許您的下載連結錯誤。
|
||||
233=請檢查連結並重試
|
||||
226=解包中
|
||||
227=已解包
|
||||
228=不是支持的格式
|
||||
229=請耐心等待直到接收完成
|
||||
230=錯誤鏈接
|
||||
231=當您下載時發生錯誤,請再嘗試!
|
||||
232=發生錯誤!也許妳的下載鏈接是錯誤的。
|
||||
233=請檢查鏈接並嘗試
|
||||
234=瀏覽網站
|
||||
235=關閉並瀏覽網站
|
||||
236=編輯
|
||||
237=切換檔案目錄
|
||||
238=選取其他
|
||||
239=資料庫已存在!
|
||||
240=如果未知請留空
|
||||
241=Apache的 SSL 連接埠預設為停用,勾選以啟用。
|
||||
242=已產生 SSL 憑證!
|
||||
243=您必須先點擊 [%s]!
|
||||
244=自動建立資料庫
|
||||
245=如何強制 Wordpress 使用相對路徑
|
||||
246=左鍵
|
||||
247=右鍵
|
||||
237=切換文檔根目錄
|
||||
238=選擇另外壹個
|
||||
239=數據庫已存在!
|
||||
240=如果不知道請留空
|
||||
241=Apache的 SSL 端口默認是關閉的,檢查後啟用
|
||||
242=生成 SSL 證書!
|
||||
243=妳必須先點擊 [%s] !
|
||||
244=自動創建數據庫
|
||||
245=如何強制Wordpress使用相對路徑
|
||||
246=左擊
|
||||
247=右擊
|
||||
248=Laragon 安裝根目錄
|
||||
249=全部刪除 [自動]
|
||||
250=設定檔
|
||||
251=啟動檔
|
||||
252=如何新增其他 %s 版本
|
||||
253=Laragon 已在執行!
|
||||
249=刪除所有 [自動]
|
||||
250=設置文件
|
||||
251=啟動文件
|
||||
252=如何添加另外壹個 %s 版本
|
||||
253=Laragon正在運行!
|
||||
|
||||
|
||||
# Reset & generate a random password for root
|
||||
803=重置並產生一個隨機的 root 密碼
|
||||
804=解決方案:重置 MySQL root 密碼
|
||||
805=偵測 MySQL 是否正在執行
|
||||
806=%s 正在執行,PID 為 %d
|
||||
807=找到一個處理程序
|
||||
808=您必須先停止 MySQL 伺服器!
|
||||
803=重置並生產壹個隨機的root密碼
|
||||
804=妳可以梳理問題,重置MySQL root密碼
|
||||
805=檢測如果MySQL正在運行
|
||||
806=%s 正在運行 PID %d
|
||||
807=發現壹個進程
|
||||
808=妳必須先停止正在運行的MySQL!
|
||||
|
||||
810=以 %s 選項啟動 MySQL 服務
|
||||
811=重置 root 密碼 & 產生一個隨機密碼
|
||||
812=已成功重置和產生 MySQL root 密碼!
|
||||
813=已複製到剪貼簿:%s
|
||||
814=發生錯誤!%s
|
||||
815=正在停止 MySQL - PID %d
|
||||
816=無法停止正在執行的 MySQL - PID %d
|
||||
817=您可以試試手動重置:%s
|
||||
810=%s 選項啟動MySQL服務
|
||||
811=重置root密碼 & 生成壹個隨機密碼
|
||||
812=重置&生成MySQL root密碼!
|
||||
813=已復制到粘貼板: %s
|
||||
814=發生錯誤! %s
|
||||
815=停止 MySQL - PID %d
|
||||
816=無法停止當前運行的 MySQL - PID %d
|
||||
817=妳需要手動重置: %s
|
||||
818=完成
|
||||
|
||||
|
||||
# Windows Explorer's Context Menu - && is not typo
|
||||
830=右鍵選單
|
||||
831=加入 Sublime Text && 終端機
|
||||
832=移除 Sublime Text && 終端機
|
||||
833=使用 Sublime Text 編輯
|
||||
834=使用 Sublime Text 打開資料夾
|
||||
836=請以管理員身分開啟 Laragon 並重試!
|
||||
830=右擊 菜單
|
||||
831=添加/更新 Sublime Text && Terminal
|
||||
832=移除 Sublime Text && Terminal
|
||||
833=使用Sublime Text編輯
|
||||
834=使用Sublime Text打開文件夾
|
||||
836=請嘗試管理員身份運行Laragon!
|
||||
|
||||
|
||||
# Setup
|
||||
900=Laragon 的執行速度飛快,且記憶體占用率極低(小於 4 MB)
|
||||
901=美化您的應用程式的網址 ---> http://app.test
|
||||
902=將 Sublime Text 和 終端機加入右鍵選單
|
||||
903=快速打開文字編輯器及終端機
|
||||
904=查看 README 文件
|
||||
905=開啟 Laragon
|
||||
|
||||
# SSL
|
||||
906 = 自動產生 SSL 憑證
|
||||
|
||||
# Version 3
|
||||
140 = 正在初始化資料...
|
||||
141 = 無法初始化資料,請重試!
|
||||
142 = Region
|
||||
150 = 將 Laragon 加入 Path 環境變數
|
||||
151 = 將 Laragon 從 Path 環境變數中移除
|
||||
152 = 管理 Path 環境變數
|
||||
153 = 已將 Laragon 加入 Path!您可能需要重新登入以套用變更。
|
||||
154 = 已將 Laragon 從 Path 中移除!
|
||||
155 = 全部關閉
|
||||
156 = 自動執行
|
||||
157 = 正在停止執行中的服務...
|
||||
158 = 幫助
|
||||
|
||||
# Version 3.1.3
|
||||
159 = 自動產生 QR Code
|
||||
|
||||
# Version 3.3.1
|
||||
160 = SSL 已啟用。點擊此處以停用
|
||||
161 = 將 laragon.crt 加入至 Trust Store
|
||||
162 = 憑證管理員
|
||||
163 = 快捷設定
|
||||
164 = 如何管理 "%s"
|
||||
165 = 如何將 Xdebug 加入 Laragon
|
||||
166 = WildcardDNS
|
||||
167 = 這是什麼?
|
||||
|
||||
# Version 3.5
|
||||
920 = 複製
|
||||
921 = 選擇要複製的專案
|
||||
922 = 已複製資料庫!
|
||||
900=Laragon運行得非常快,具有非常低的內存占用(小於4 MB)
|
||||
901=妳的“項目”將得到優雅鏈接 ---> https://項目.test
|
||||
902=添加 Sublime Text 和 Terminal 到右擊菜單
|
||||
903=快速打開 文本編輯器 和 命令行
|
||||
904=查看README文件
|
||||
905=運行Laragon
|
||||
@@ -1,6 +1,6 @@
|
||||
--------------------------------------------------------
|
||||
version: 1.0
|
||||
author: Claus Munch - claus@codepoint.dk - http://codepoint.dk
|
||||
author: Claus Munch - claus@codepoint.dk - https://codepoint.dk
|
||||
date: 20160511
|
||||
--------------------------------------------------------
|
||||
# Main Interface
|
||||
|
||||
@@ -250,7 +250,7 @@ date: 20201115
|
||||
|
||||
# Setup
|
||||
900 = Laragon functioneert extreem snel en heeft een zeer laag geheugen verbruik (< 4 MB)
|
||||
901 = Je app zal een mooie url krijgen ---> http://app.test
|
||||
901 = Je app zal een mooie url krijgen ---> https://app.test
|
||||
902 = Toevoegen Sublime Text && Terminal aan het Rechtermuisklik Menu
|
||||
903 = Snelle manieren om Tekstverwerker en Opdrachtprompt te openen
|
||||
904 = Bekijken het README bestand
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
--------------------------------------------------------
|
||||
version: 3.5
|
||||
version: 7.0.1
|
||||
author: leokhoa - leokhoa at gmail.com - https://laragon.org
|
||||
date: 20181016
|
||||
date: 20250124
|
||||
--------------------------------------------------------
|
||||
# Main Interface
|
||||
100 = Start All
|
||||
@@ -111,7 +111,7 @@ date: 20181016
|
||||
501 = Left click: Open Laragon - Right click: Menu
|
||||
502 = Start page
|
||||
503 = Database Management
|
||||
504 = Open Command Prompt (Hotkey: CTRL+ALT+T)
|
||||
504 = Open Terminal (Cmder)
|
||||
505 = Laragon will call nodejs to create virtual hosts for you\nIf you want this feature without calling nodejs:\nRun Laragon as Administrator
|
||||
506 = Document Root
|
||||
|
||||
@@ -250,7 +250,7 @@ date: 20181016
|
||||
|
||||
# Setup
|
||||
900 = Laragon runs extremely fast and has a very low memory footprint (< 4 MB)
|
||||
901 = Your app will get a pretty url ---> http://app.test
|
||||
901 = Your app will get a pretty url ---> https://app.test
|
||||
902 = Add Sublime Text && Terminal to the Right-Click Menu
|
||||
903 = Quick ways to open Text Editor & Command Prompt
|
||||
904 = View the README file
|
||||
@@ -290,3 +290,10 @@ date: 20181016
|
||||
920 = Clone
|
||||
921 = Select a project to clone
|
||||
922 = Cloned database!
|
||||
|
||||
# version 7.0 Laragon 2025
|
||||
929 = Current profile
|
||||
930 = New profile
|
||||
931 = Profile Name
|
||||
932 = Action
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ date: 20181219
|
||||
|
||||
# Setup
|
||||
900=Laragon se lance extrêmement rapidement et a une empreinte mémoire très basse (< 4 MB)
|
||||
901=Votre application aura une jolie URL ---> http://app.test
|
||||
901=Votre application aura une jolie URL ---> https://app.test
|
||||
902=Ajouter Sublime Text et le terminal au menu contextuel
|
||||
903=Façon rapide d'ouvrir l'éditeur de texte et le terminal
|
||||
904=Voir le fichier README
|
||||
|
||||
@@ -250,7 +250,7 @@ date: 20160715
|
||||
|
||||
# Setup
|
||||
900=Laragon läuft extrem performant und hat einen sehr geringen Speicherverbrauch (< 4 MB)
|
||||
901=Ihre Anwendung bekommt diese URL ---> http://app.test
|
||||
901=Ihre Anwendung bekommt diese URL ---> https://app.test
|
||||
902=Sublime Text && Terminal zum Kontextmenü hinzufügen
|
||||
903=Schnelles öffnen des Text-Editors und der Konsole
|
||||
904=README-Datei öffnen
|
||||
|
||||
@@ -247,7 +247,7 @@ date: 20161025
|
||||
|
||||
# Setup
|
||||
900=Το Laragon είναι ταχύτατο και καταναλώνει ελάχιστη μνήμη (< 4 MB)
|
||||
901=Η εφαρμογή σου θα αποκτήσει pretty url ---> http://app.test
|
||||
901=Η εφαρμογή σου θα αποκτήσει pretty url ---> https://app.test
|
||||
902=Προσθήκη του Sublime Text && Τερματικό στο μενού του δεξιού κλικ
|
||||
903=Φρήγοροι τρόποι να ανοίξεις τον επεξεργαστή κειμένου και το τερματικό
|
||||
904=Δες το αρχείο README
|
||||
|
||||
@@ -250,7 +250,7 @@ date: 20191016
|
||||
|
||||
# Setup
|
||||
900 = A Laragon rendkívül gyors és alacsony memóriaigényű alkalmazás (< 4 MB)
|
||||
901 = Alkalmazása szép url-t kap ---> http://app.test a http://localhost/app helyett
|
||||
901 = Alkalmazása szép url-t kap ---> https://app.test a https://localhost/app helyett
|
||||
902 = Sublime Text és Terminál hozzáadása az intéző helyi menüjéhez
|
||||
903 = Így a szövegszerkesztő és a parancssoros terminál gyors megnyitható
|
||||
904 = README (olvass el) fájl megnyitása
|
||||
|
||||
@@ -250,7 +250,7 @@ date: 20181016
|
||||
|
||||
# Setup
|
||||
900 = Laragon berjalan sangat cepat dan memiliki jejak memori yang sangat rendah (< 4 MB)
|
||||
901 = Aplikasi Anda akan mendapatkan url yang cantik ---> http://app.test dari pada http://localhost/app
|
||||
901 = Aplikasi Anda akan mendapatkan url yang cantik ---> https://app.test dari pada https://localhost/app
|
||||
902 = Tambhakan Sublime Text && Terminal ke Menu Klik Kanan
|
||||
903 = Cara cepat untuk membuka Editor Teks & Command Prompt
|
||||
904 = Lihat file README
|
||||
|
||||
@@ -250,7 +250,7 @@ date: 20160821
|
||||
|
||||
# Setup
|
||||
900=Laragon gira estremamente veloce e occupa poco spazio di memoria (< 4 MB)
|
||||
901=La tua app avrà una pretty url ---> http://app.test
|
||||
901=La tua app avrà una pretty url ---> https://app.test
|
||||
902=Aggiungi Sublime Text && Terminale al menu contestuale
|
||||
903=Avvio veloce per aprire Text Editor & Command Prompt
|
||||
904=Mostra il file README
|
||||
|
||||
@@ -250,7 +250,7 @@ date: 20181016
|
||||
|
||||
# Setup
|
||||
900 = Laragonは、ほんの少しのメモリ消費でとても軽快に走ります (< 4 MB)
|
||||
901 = あなたのアプリはとても愛らしいURLになりますよ ---> http://app.test
|
||||
901 = あなたのアプリはとても愛らしいURLになりますよ ---> https://app.test
|
||||
902 = 右クリックメニューにSublime Text && Terminalを追加する
|
||||
903 = テキストエディタとコマンドプロンプトを開く簡単な方法
|
||||
904 = README ファイルを見る
|
||||
|
||||
@@ -250,7 +250,7 @@ date: 20181016
|
||||
|
||||
# Setup
|
||||
900 = 라라곤은 매우 빠르게 실행되며 메모리 사용량이 매우 적습니다 (< 4MB)
|
||||
901 = 당신의 앱은 http://localhost/app 대신에 예쁜 url을 얻을 것입니다 ---> http://app.test
|
||||
901 = 당신의 앱은 https://localhost/app 대신에 예쁜 url을 얻을 것입니다 ---> https://app.test
|
||||
902 = 오른쪽 클릭 메뉴에 서브라임 에디터 및 터미널 추가
|
||||
903 = 텍스트 편집기 및 명령 프롬프트를 여는 빠른 방법
|
||||
904 = README 파일보기
|
||||
|
||||
@@ -249,7 +249,7 @@ date: 20181123
|
||||
|
||||
# Setup
|
||||
900 = Laragon berjalan dengan sangat pantas dan mempunyai jejak memori yang sangat rendah (< 4 MB)
|
||||
901 = Apl anda akan mendapat url cantik ---> http://app.test
|
||||
901 = Apl anda akan mendapat url cantik ---> https://app.test
|
||||
902 = Tambah Sublime Text && Terminal ke Menu Klik-Kanan
|
||||
903 = Cara pantas untuk buka Editor Teks & Arahan Prompt
|
||||
904 = Papar fail BACASAYA
|
||||
|
||||
@@ -250,7 +250,7 @@ Dato: 26.06.2017
|
||||
|
||||
# Setup
|
||||
900=Laragon kjører ekstremt fort og har svært lavt minnefottrykk (<4 MB)
|
||||
901=Appen din vil få normal url ---> http://app.test
|
||||
901=Appen din vil få normal url ---> https://app.test
|
||||
902=Legg til Sublime Text && Terminal til Høyreklikk-menyen
|
||||
903=Rask måter å åpne tekstredigerer og kommandoprompt
|
||||
904=Se Lesemeg-filen
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
--------------------------------------------------------
|
||||
--------------------------------------------------------
|
||||
version: 2.0.5
|
||||
version: 3.5
|
||||
author: Milad GanjAli - miladstory@gmail.com
|
||||
date: 20161121
|
||||
author: Keramat Jokar - keramatjokar8855@gmail.com
|
||||
date: 20250111
|
||||
--------------------------------------------------------
|
||||
# Main Interface
|
||||
100 = همه را شروع کن
|
||||
@@ -36,7 +36,6 @@ date: 20161121
|
||||
202 = انتقال فایل ها
|
||||
203 = ایجاد پروژه
|
||||
204 = تغییر پروژه
|
||||
|
||||
205 = ایجاد پایگاه داده
|
||||
206 = تغییر رمز روت
|
||||
207 = ایمیل گیر
|
||||
@@ -125,7 +124,7 @@ date: 20161121
|
||||
604 = در حال استخراج
|
||||
605 = استخراج شد
|
||||
606 = تارنما زیبا ایجاد گردید
|
||||
607 = ایجاد سزیع
|
||||
607 = ایجاد سریع
|
||||
608 = نام وب سایت
|
||||
609 = لطفا نام پروژه را مشخص فرمائید!
|
||||
610 = ایجاد شد %s!
|
||||
@@ -252,7 +251,7 @@ date: 20161121
|
||||
|
||||
# Setup
|
||||
900 = لاراگون بسیار سریع اجرا می شود و دارای ردپای کمی در حافظه میباشد (< 4 MB)
|
||||
901 = برنامه شما URL زیبا را دریافت می کند ---> http://app.test
|
||||
901 = برنامه شما URL زیبا را دریافت می کند ---> https://app.test
|
||||
902 = اضافه کردن Notepad++ و ترمینال به منوی راست کلیک
|
||||
903 = راه های سریع برای باز کردن ویرایشگر متن و خط فرمان
|
||||
904 = فایل READMe را مشاهده کنید
|
||||
@@ -260,3 +259,35 @@ date: 20161121
|
||||
|
||||
# SSL
|
||||
906 = تولید خودکار گواهی SSL
|
||||
|
||||
# Version 3
|
||||
140 = در حال مقدار دهی اولیه داده ها...
|
||||
141 = داده ها را نمی توان مقداردهی اولیه کرد، لطفا دوباره امتحان کنید!
|
||||
142 = منطقه
|
||||
150 = افزودن لاراگون به Path
|
||||
151 = حذف لاراگون از Path
|
||||
152 = مدیریت Path
|
||||
153 = لاراگون به Path اضافه شد! برای اعمال تغییرات ممکن است لازم باشد از سیستم خارج شوید و دوباره وارد شوید.
|
||||
154 = لاراگون از Path حذف شد!
|
||||
155 = بستن همه
|
||||
156 = اجرای خودکار
|
||||
157 = توقف اجرای سرویس ها...
|
||||
158 = کمک
|
||||
|
||||
# Version 3.1.3
|
||||
159 = کد QR خودکار تولید شده
|
||||
|
||||
# Version 3.3.1
|
||||
160 = SSL فعال است. برای غیرفعال کردن کلیک کنید
|
||||
161 = افزودن laragon.crt را به Trust Store
|
||||
162 = مدیرت گواهی
|
||||
163 = تنظیمات سریع
|
||||
164 = چگونه "%s" را مدیریت کنیم
|
||||
165 = چگونه Xdebug را به لاراگون اضافه کنیم
|
||||
166 = WildcardDNS
|
||||
167 = این چیست؟
|
||||
|
||||
# Version 3.5
|
||||
920 = کلون
|
||||
921 = پروژه ای را برای کلون کردن انتخاب کنید
|
||||
922 = پایگاه داده کلون شده!
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--------------------------------------------------------
|
||||
version: 2.0.4
|
||||
author: Błażej Hap - blazejhap@gmail.com - http://conit-group.pl
|
||||
author: Błażej Hap - blazejhap@gmail.com - https://conit-group.pl
|
||||
modified by: Manam
|
||||
date: 20160802
|
||||
--------------------------------------------------------
|
||||
@@ -250,7 +250,7 @@ date: 20160802
|
||||
|
||||
# Setup
|
||||
900=Laragon działa ekstremalnie szybko i zajmuje bardzo mało pamięci (< 4 MB)
|
||||
901=Twoja aplikacja będzie dostępna pod wygodnym adresem ---> http://app.test
|
||||
901=Twoja aplikacja będzie dostępna pod wygodnym adresem ---> https://app.test
|
||||
902=Dodaj 'Sublime Text' i 'Terminal' do menu pod prawm klawiszem myszy
|
||||
903=Szybki sposób, aby otworzyć 'Edytor tekstu' i 'Wiersz poleceń'
|
||||
904=Pokaż plik README
|
||||
|
||||
@@ -236,7 +236,7 @@ date: 20190729
|
||||
|
||||
# Setup
|
||||
900 = Laragon é executado extremamente rápido e tem um rasto na memória muito baixa (<4 MB)
|
||||
901 = Seu aplicativo receberá um URL bonito ---> http://app.test
|
||||
901 = Seu aplicativo receberá um URL bonito ---> https://app.test
|
||||
902 = Adicionar texto sublime && Terminal ao menu do botão direito
|
||||
903 = Formas rápidas de abrir o Editor de Texto e o Prompt de Comando
|
||||
904 = Visualizar o arquivo README
|
||||
|
||||
@@ -250,7 +250,7 @@ date: 20191215
|
||||
|
||||
# Установка
|
||||
900 = Laragon работает очень быстро и имеет очень низкий объем памяти (менее 4 МБ)
|
||||
901 = Ваше приложение получит удобный URL ---> http://app.test
|
||||
901 = Ваше приложение получит удобный URL ---> https://app.test
|
||||
902 = Добавить Sublime Text и Терминал в контекстное меню Windows
|
||||
903 = Быстрый способ открыть текстовый редактор и командную строку
|
||||
904 = Посмотреть файл README
|
||||
|
||||
@@ -250,7 +250,7 @@ date: 20200801
|
||||
|
||||
# Nastavitve
|
||||
900 = Laragon deluje zelo hitro in ima zelo nizko rabo pomnilnika (<4 MB)
|
||||
901 = Vaša aplikacija bo dobila lep URL ---> http://app.test
|
||||
901 = Vaša aplikacija bo dobila lep URL ---> https://app.test
|
||||
902 = Dodaj Sublime Text && Terminal na kontekstualni meni desnega klika
|
||||
903 = Hitri načini za odpiranje urejevalnika besedil in ukazne vrstice (Command Prompt)
|
||||
904 = Ogled datoteke README
|
||||
|
||||
@@ -250,7 +250,7 @@ date: 20200527
|
||||
|
||||
# Setup
|
||||
900 = Laragon Körs och är extremt snabb,har mycket lågt minnesavtryck (< 4 MB)
|
||||
901 = Din app kommer få vackra länkar ---> http://app.test
|
||||
901 = Din app kommer få vackra länkar ---> https://app.test
|
||||
902 = Lägg Sublime Text && Terminal till högerklickmenyn
|
||||
903 = Snabbt sätt att öppna Text Editor och Command Prompt
|
||||
904 = Visa README-filen
|
||||
|
||||
@@ -251,7 +251,7 @@ date: 20191013
|
||||
|
||||
# Setup
|
||||
900 = Laragon son derece hızlı çalışır ve çok az bellek kaplar (< 4 MB)
|
||||
901 = Uygulama adresleriniz ---> http://app.test
|
||||
901 = Uygulama adresleriniz ---> https://app.test
|
||||
902 = Sağ tıklama menüse Sublime Text ve Terminal ekle
|
||||
903 = Metin Düzenleyici ve Komut İstemi'ni açmanın hızlı yolları
|
||||
904 = Benioku dosyasını görüntüle
|
||||
|
||||
@@ -251,7 +251,7 @@ date: 20170703
|
||||
|
||||
# Setup
|
||||
900 = Laragon дуже швидко працює та споживає дуже мало оперативної пам`яті (< 4 MB)
|
||||
901 = Ваш додаток отримає гарний URL ---> http://app.test
|
||||
901 = Ваш додаток отримає гарний URL ---> https://app.test
|
||||
902 = Додати Sublime Text && Terminal в контекстне меню правою кнопкою мишки
|
||||
903 = Швидкі методи відкрити Текстовий Редактор & Командний Рядок
|
||||
904 = Переглянути README файл
|
||||
|
||||
@@ -70,7 +70,7 @@ date: 20160919
|
||||
320=Click để thay đổi thư mục chứa dữ liệu của MySQL
|
||||
|
||||
322=Tự động tạo host ảo
|
||||
323=Đưa thư mục <name> vào Document Root, Laragon sẽ tạo link đẹp cho bạn --> http://name.test
|
||||
323=Đưa thư mục <name> vào Document Root, Laragon sẽ tạo link đẹp cho bạn --> https://name.test
|
||||
|
||||
# %s for a string placeholder
|
||||
324=Định dạng
|
||||
@@ -252,7 +252,7 @@ date: 20160919
|
||||
|
||||
# Setup
|
||||
900=Laragon chạy cực nhanh và dùng rất ít bộ nhớ (< 4 MB)
|
||||
901=app của bạn sẽ có link đẹp ---> http://app.test
|
||||
901=app của bạn sẽ có link đẹp ---> https://app.test
|
||||
902=Thêm Sublime Text && Terminal vào Menu Phải
|
||||
903=Giúp bạn mở trình soạn thảo và gõ lệnh nhanh chóng
|
||||
904=Xem README
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,198 +0,0 @@
|
||||
Change Log
|
||||
============================
|
||||
### Version 2.0 ###
|
||||
|
||||
SimpleAjaxUploader.js:
|
||||
|
||||
* Added support for drag and drop file uploads
|
||||
* Added `ss.uploadSetup()` method to set default uploader option values (useful for multiple uploader instances)
|
||||
* Added `noParams` option to disable the default behavior of appending the file name to the URL query string
|
||||
* Numerous code improvements throughout -- bug fixes, memory usage, etc.
|
||||
|
||||
Uploader.php
|
||||
* Refactored into a single class in accordance with one class, one file
|
||||
* Made improvements to error detection and handling
|
||||
* Added support for reading the `X-File-Name` header as an alternative to query string parameters for sending file names to the server
|
||||
* Set default value of the `$uploadName` property to be `"uploadfile"` for consistency with the examples - <a href="https://github.com/LPology/Simple-Ajax-Uploader/issues/72">72</a>
|
||||
|
||||
### Version 1.11 ###
|
||||
* Added support for PHP Session Upload Progress for PHP 5.4+ (APC was deprecated in 5.3)
|
||||
* Added `clearQueue()` method which gives the user the ability to clear all files in queue - <a href="https://github.com/LPology/Simple-Ajax-Uploader/pull/62">#62</a> - (Special thanks to <a href="https://github.com/mouse0270">mouse0270</a> for this one)
|
||||
* Fixed multiple file selection bug - <a href="https://github.com/LPology/Simple-Ajax-Uploader/pull/67">#67</a> - (Special thanks to <a href="https://github.com/genintho">genintho</a> for this)
|
||||
* Fixed bug which could allow form/input elements to be created with invalid name/ID attributes in IE7-9
|
||||
|
||||
### Version 1.10.1 ###
|
||||
* `iframe` and `form` elements are now created with `document.createElement()` rather than the much slower HTML injection method
|
||||
* Removed unused variable from `_uploadIframe()`
|
||||
|
||||
### Version 1.10 ###
|
||||
* Added `setOptions()` method for setting or changing upload options - <a href="https://github.com/LPology/Simple-Ajax-Uploader/issues/54">#54</a> - (special thanks to <a href="https://github.com/hauru">hauru</a> for this)
|
||||
* Added `customHeader` option for sending custom request headers - <a href="https://github.com/LPology/Simple-Ajax-Uploader/issues/47">#47</a> (special thanks to <a href="https://github.com/cillosis">cillosis</a> for this)
|
||||
* Updated `ss.parseJSON()` to use a more secure method of manually parsing JSON
|
||||
|
||||
### Version 1.9.1 ###
|
||||
* `onError()` callback now receives server response as an argument, if it exists, or `false` if it does not - <a href="https://github.com/LPology/Simple-Ajax-Uploader/pull/37">#37</a> (special thanks to <a href="https://github.com/KSDaemon">KSDaemon</a> for this)
|
||||
<br />
|
||||
<br />
|
||||
<strong>API Change Note:</strong> For consistency with the other callbacks, the server response is passed to `onError()` as the next to last argument, directly before the upload button. Therefore, if you use the upload button parameter in `onError()`, you will need to update your code when upgrading.
|
||||
<br />
|
||||
<br />
|
||||
* Switched from Google Closure Compiler to YUI Compressor for minification
|
||||
|
||||
### Version 1.9 ###
|
||||
* Added CORS support - <a href="http://www.lpology.com/code/ajaxuploader/How-to-Cross-Domain-File-Uploading.php">Learn more</a>
|
||||
* Query string parameters for Nginx Upload Progress Module in `_uploadIframe()` are now encoded with `encodeURIComponent()`
|
||||
* Upload progress ID keys are now generated prior to each upload instead of on page load
|
||||
* Query string parameters passed to `url` are now preserved - <a href="https://github.com/LPology/Simple-Ajax-Uploader/issues/34">#34</a> (special thanks to <a href="https://github.com/Deefjuh">Deefjuh</a> for this)
|
||||
|
||||
### Version 1.8.2 ###
|
||||
* A reference to the button which triggers an upload is now passed as the last argument to the following callbacks: `onAbort()`, `onChange()`, `onSubmit()`, `onComplete()`, `onError()`, `startXHR()`, `endXHR()`, `startNonXHR()`, `endNonXHR()` (can be useful when using multiple upload buttons)
|
||||
* Fixed bug which caused some methods to not work if called inside of `startXHR()` or `startNonXHR()`
|
||||
* Fixed bug causing undefined variable in IE9 and older if `progressUrl` and `nginxProgressUrl` are not set
|
||||
|
||||
### Version 1.8.1 ###
|
||||
* Added `destroy()` method for completely removing upload functionality
|
||||
* Removed redundant call to `ss.verifyElem()` inside of `rerouteClicks()`
|
||||
* Moved browser-specific checks to top of IIFE, as they only need to execute once
|
||||
|
||||
### Version 1.8 ###
|
||||
SimpleAjaxUploader.js:
|
||||
* Added support for <a href="http://wiki.nginx.org/HttpUploadProgressModule">Nginx Upload Progress Module</a>
|
||||
* Added `setAbortBtn()` method to designate an element as "cancel" button
|
||||
* Added `onAbort()` callback function to specify behavior upon manual abort
|
||||
* Added `setPctBox()` method to designate an element to be injected with upload progress percentage
|
||||
* Switched to a unique ID function that is RFC 4122 version 4 compliant
|
||||
* The `button` option now accepts either a single button (element ID string, element, or jQuery object), or an array of buttons. If an array is passed, each element in the array will work as an upload button
|
||||
* Upload progress update request keys are now locally generated
|
||||
* Fixed bug that was causing `onError()` to be fired twice
|
||||
* For consistency with jQuery behavior, any 2xx status code is now handled as a successful response (previously, only `200` and `201` were successful)
|
||||
* Upload buttons are now being properly disabled/enabled at correct points
|
||||
* Made significant improvements to error handling, particularly with iframe uploads and retrieving server provided progress updates
|
||||
* Fixed a number of potential memory leaks for Internet Explorer
|
||||
* Regular expressions are now pre-compiled and cached for better performance
|
||||
* For server progress tracking, `sizeBox` and `onUpdateFileSize()` are no longer pointlessly set/called again after first progress update is received
|
||||
|
||||
uploadProgress.php:
|
||||
* Removed functionality for returning upload keys, as RFC 4122 v4 compliant UUIDs are now generated client side
|
||||
|
||||
### Version 1.7 ###
|
||||
SimpleAjaxUploader.js:
|
||||
* Fixed IE6/IE7 memory leak when removing elements without first removing event listeners (<a href="https://github.com/LPology/Simple-Ajax-Uploader/issues/21">issue #21</a>)
|
||||
* Fixed possible race condition in which `removeCurrent()` could potentially delete the wrong file from the upload queue
|
||||
* Multiple file inputs are now disabled in Safari due to a browser bug that just screws everything up (see: http://stackoverflow.com/q/7231054/1091949)
|
||||
* Switched to a smaller, faster process for cross-browser bounding box calculation
|
||||
* Updated to faster methods of checking for, adding, and removing element CSS classes
|
||||
* Combined `_checkExtension()` with `_checkFile()` to eliminate a function call/reduce code size
|
||||
* Combined `_handleIframeResponse()` with `_uploadIframe()` and switched to a more efficient method of getting iframe contents
|
||||
* Removed a number of unnecessary/redundant function calls, along with some unnecessary variable copying
|
||||
* Updated `ss.verifyElem()` to use the much faster `charAt()` and `substr()` in place of a regex and `slice()`
|
||||
* Added separate feature detection for file input `accept` attribute
|
||||
|
||||
Uploader.php:
|
||||
* Removed unnecessary check of `$allowedExtensions` for `null` value in `handleUpload()`
|
||||
* Added `final` keyword to `FileUploadXHR` and `FileUploadPOSTForm` classes and their respective methods to discourage direct use
|
||||
|
||||
### Version 1.6.5 ###
|
||||
* When using `multipart`, additional data will now also appended to the multipart form.
|
||||
* Cleaned up some messy code -- organization, unnecessary variable copying, etc.
|
||||
|
||||
### Version 1.6.4 ###
|
||||
* Switched from using `setAttribute` to dot notation for setting element properties (some versions of IE don't handle `setAttribute` well)
|
||||
* `ss.removeItem()` now uses the faster countdown method to loop through arrays
|
||||
* In accordance with W3 standards, `_uploadXhr()` now accepts either a `200 OK` or `201 Created` as a successful response
|
||||
* Uploader.php -- the `handleUpload()` method now checks whether the `allowedExtensions` property is `empty` instead of `null`. This prevents an "Invalid file type" error resulting from passing an empty array
|
||||
|
||||
### Version 1.6.3 ###
|
||||
* Fixed bug which allowed `onComplete()` to be called after JSON parse error
|
||||
|
||||
### Version 1.6.2 ###
|
||||
* Overhauled error handling to fix a number of issues.
|
||||
* Added consistent error types for `onError()` so that the second parameter will be either:
|
||||
`parseerror` (bad JSON from server), `transfererror` (xfer error during XHR upload), `servererror` (server response not `200 OK`)
|
||||
* Fixed problem with null file size parameter for `endXHR()` callback
|
||||
|
||||
### Version 1.6.1 ###
|
||||
* Plugin is now wrapped in an IIFE
|
||||
* Leading semicolon added to close any previous statement
|
||||
* Code is now in strict mode
|
||||
* Cleaned up a few messy areas
|
||||
|
||||
### Version 1.6 ###
|
||||
If the 1.6 release has a theme, it is flexibility. Nearly every update in this release is intended to allow greater flexibility for developers.
|
||||
|
||||
* Submitting a file which exceeds `maxSize` or is not an `allowedExtension` no longer triggers an alert, but will instead fire a callback
|
||||
* Added `onSizeError()` callback function which fires when a file exceeds the `maxSize` option, if it is set
|
||||
* Added `onExtError()` callback which fires when a file is not permitted by the `allowedExtensions` option, if it is set
|
||||
* Removed `messages` option and `_errorMsg()`, both of which are no longer used
|
||||
* Added new `accept` option, the value of which will be the value of the `accept` file input attribute in supporting browsers. <a href="http://stackoverflow.com/a/10503561/1091949">More info.</a>
|
||||
* Added new `method` option to allow specifying an HTTP method other than POST
|
||||
|
||||
Special thanks to <a href="https://github.com/dleffler">dleffler</a>, <a href="https://github.com/devtrends">devtrends</a> and <a href="https://github.com/urcadox">urcadox</a> for their ideas and feedback.
|
||||
|
||||
### Version 1.5.3 ###
|
||||
* Added `autoSubmit` check before submitting in `_cycleQueue()`
|
||||
* Added check to ensure upload progress server key doesn't exceed 57 characters (max allowable APC key length)
|
||||
* `rerouteClicks(element)` can now be used to add additional elements which can be clicked to open file box
|
||||
|
||||
### Version 1.5.2 ###
|
||||
(This isn't as much a release as it is a signal to update for anyone who may have downloaded version 1.5.1 in the past few hours)
|
||||
* Fixed "bug" from 1.5.1 that broke uploader without multiple option enabled
|
||||
* Added `queue` option to disable automatic file queuing
|
||||
|
||||
### Version 1.5.1 ###
|
||||
* Multiple file inputs are now used in browsers with support for File API, thus allowing multiple file selection if `multiple` option is `true`
|
||||
* Removed some unnecessary variable copying
|
||||
* Added queue system which allows files to be selected and automatically uploaded as others finish
|
||||
* Added `getQueueSize()` function to get current number of files waiting in queue
|
||||
* Fixed bug in which active upload counter was not properly updating when returning `false` from `startXHR()` and `startNonXHR()`
|
||||
* Error messages now incorporate file names
|
||||
|
||||
### Version 1.5 ###
|
||||
* Added support for multiple file uploading, along with Gmail-style multiple progress bars for tracking each file.
|
||||
* Added new `maxSize` option for file size limits, `allowedExtensions` option for file type restrictions. Custom error messages supported for both.
|
||||
* Updated `verifyElem()` to use a better method of detecting if an upload button is a jQuery object.
|
||||
* Numerous code enhancements throughout - updated error handling, cleaner organization, performance improvements.
|
||||
* Patched some memory leaks created by circular references in event handlers.
|
||||
|
||||
### Version 1.4.2 ###
|
||||
* SimpleAjaxUploader.js - Added `multipart` option to allow multipart form upload instead of binary stream
|
||||
* Uploader.php - The check for form uploads is now first in the constructor to accomodate new `multipart` option
|
||||
* Uploader.php - Providing an array of valid file extensions is now optional. If not provided, all file types are allowed
|
||||
* Added minified version of JS file
|
||||
|
||||
### Version 1.4.1 ###
|
||||
* Fixed XHR status check logic that could allow false alarm calls to onError callback
|
||||
* Removed redundant XHR status check
|
||||
* Returning false from a callback no longer clears the file field. Not sure why it ever did to begin with.
|
||||
* A status check now occurs prior to progress update requests to prevent potential loop that could be caused by a server error
|
||||
* Parsing JSON in older browsers no longer uses `eval` because it's evil
|
||||
|
||||
### Version 1.4 ###
|
||||
This release includes a major overhaul that adds functionality for implementing cross-browser upload progress support. Through feature detection and abstraction, it is now possible for the `onProgress` callback function to maintain consistent behavior across browsers.
|
||||
|
||||
Currently, only PHP (with APC extension) is supported. To use, set the newly added `progressUrl` option to the URL of the included UploadProgress.php script, and `onProgress` will then return upload progress data in Internet Explorer 9 and below.
|
||||
|
||||
Note that this added functionality does not affect the behavior of the plugin for those not using PHP, or just not using the feature.
|
||||
|
||||
For those not using PHP, a similar result can still be achieved with the `startXH`/`endXHR` and `startNonXHR`/`endNonXHR` callback functions, which are included specifically for defining behavior based on whether XHR uploads are supported.
|
||||
|
||||
Also, adding support for other programming languages would certainly be a welcome addition, if anyone is interested in working on that.
|
||||
|
||||
Other items:
|
||||
|
||||
* Added `onUpdateFileSize` callback function for getting file size in IE9 and below (When server supported progress is enabled)
|
||||
* Removed the unneccessary _handleJSON method
|
||||
* Added new ss.newXHR method
|
||||
* Added extras folder for non-necessary items (i.e., everything but SimpleAjaxUploader.js)
|
||||
* Adjusted request headers for XHR uploads
|
||||
* Moved support detection for HTML5 File API to constructor so it only executes once
|
||||
* Timestamps now appended to URLs to prevent browsers from caching requests
|
||||
|
||||
### Version 1.3 ###
|
||||
* Returned to version numbering
|
||||
* Updated method for parsing JSON
|
||||
* Added PHP class for handling file uploads
|
||||
* Cleaned up messy areas
|
||||
|
||||
### Earlier versions ###
|
||||
Prior to version 1.3, I did a pretty horrible job of documenting changes, and, at one point, entirely dispensed with any notion of version control whatsoever. I have since seen the light.
|
||||
@@ -1,258 +0,0 @@
|
||||
Simple Ajax Uploader
|
||||
============================
|
||||
|
||||
A Javascript plugin for cross-browser Ajax file uploading. Supports drag and drop, CORS, and multiple file uploading with progress bars. Works in IE7-9, mobile, and all modern browsers.
|
||||
|
||||
```javascript
|
||||
var uploader = new ss.SimpleUpload({
|
||||
button: 'upload-btn', // HTML element used as upload button
|
||||
url: '/PathTo/UploadHandler', // URL of server-side upload handler
|
||||
name: 'uploadfile' // Parameter name of the uploaded file
|
||||
});
|
||||
```
|
||||
|
||||
### Features ###
|
||||
* Cross-browser -- works in IE7+, Firefox, Chrome, Safari, Opera
|
||||
* Supports multiple, concurrent file uploads (even in non-HTML5 browsers)
|
||||
* Built-in CORS support
|
||||
* Drag and drop file uploads (<strong>new in v2.0</strong>)
|
||||
* No flash or external CSS -- a single 6Kb Javascript file (minified and gzipped)
|
||||
* Progress bars in all browsers, including IE9 and older. Built-in support for:
|
||||
* <a href="http://wiki.nginx.org/HttpUploadProgressModule">Nginx Upload Progress Module</a>
|
||||
* <a href="http://www.php.net/manual/en/apc.configuration.php#ini.apc.rfc1867">PHP APC File Upload Progress</a>
|
||||
* <a href="http://php.net/manual/en/session.upload-progress.php">PHP Session Upload Progress</a>
|
||||
* Use any HTML element as the upload button
|
||||
* No dependencies - use it with or without jQuery
|
||||
* Provides individual callback functions for XHR-supported browsers and for browsers that do not support XHR uploads
|
||||
* Ability to pass custom headers in request such as the Authorization header
|
||||
|
||||
### How to Use ###
|
||||
|
||||
<a href="https://www.lpology.com/code/ajaxuploader/">Live Demo</a><br />
|
||||
<a href="https://www.lpology.com/code/ajaxuploader/docs.php">API Reference</a><br />
|
||||
<a href="https://www.lpology.com/code/ajaxuploader/progress.php">Upload progress bars in IE9 (and older)</a><br />
|
||||
<a href="https://www.lpology.com/code/ajaxuploader/How-to-Cross-Domain-File-Uploading.php">CORS — Cross-domain file uploading with Simple Ajax Uploader</a>
|
||||
|
||||
There are two main ways to use the plugin:
|
||||
|
||||
<strong>1. Single file uploading</strong> - Only one upload allowed at a time. Progress bar is an element that is re-used for each upload.<br />
|
||||
<strong>2. Multiple file uploading</strong> - Allow multiple, concurrent file uploads. Progress bars are created on the fly before each upload.
|
||||
|
||||
#### Method 1: Single file uploading (one file at a time) ####
|
||||
|
||||
Before each upload, in the `onSubmit()` callback function, the on-page <code>sizeBox</code> and <code>progress</code> elements are assigned specific roles using these two functions:
|
||||
|
||||
`setProgressBar(elem)` - Designates an element as the progress bar for an upload.<br />
|
||||
`setFileSizeBox(elem)` - Designates an element as the container in which the file size of an uploading file will be inserted.
|
||||
|
||||
As a result, when an upload begins, the file size of the upload is inserted into the <code>sizeBox</code> element and the CSS width of the <code>progress</code> element is set to 0%. As the upload progresses, the CSS width percentage of the <code>progress</code> element will be updated accordingly.
|
||||
|
||||
This approach of assigning roles to elements provides developers with a great deal of flexibility -- progress indicators can be styled in any way and placed anywhere on the page.
|
||||
|
||||
```javascript
|
||||
var sizeBox = document.getElementById('sizeBox'), // container for file size info
|
||||
progress = document.getElementById('progress'); // the element we're using for a progress bar
|
||||
|
||||
var uploader = new ss.SimpleUpload({
|
||||
button: 'uploadButton', // file upload button
|
||||
url: 'uploadHandler.php', // server side handler
|
||||
name: 'uploadfile', // upload parameter name
|
||||
progressUrl: 'uploadProgress.php', // enables cross-browser progress support (more info below)
|
||||
responseType: 'json',
|
||||
allowedExtensions: ['jpg', 'jpeg', 'png', 'gif'],
|
||||
maxSize: 1024, // kilobytes
|
||||
hoverClass: 'ui-state-hover',
|
||||
focusClass: 'ui-state-focus',
|
||||
disabledClass: 'ui-state-disabled',
|
||||
onSubmit: function(filename, extension) {
|
||||
this.setFileSizeBox(sizeBox); // designate this element as file size container
|
||||
this.setProgressBar(progress); // designate as progress bar
|
||||
},
|
||||
onComplete: function(filename, response) {
|
||||
if (!response) {
|
||||
alert(filename + 'upload failed');
|
||||
return false;
|
||||
}
|
||||
// do something with response...
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
#### Method 2: Multiple file uploads ####
|
||||
|
||||
Below is an example of how to implement multiple file uploading with progress bars. A new progress bar is created for each file upload within the `onSubmit()` callback function.
|
||||
|
||||
Like in Method 1, the newly created elements are assigned roles using the `setProgressBar()` and `setFileSizeBox()` functions. Unlike the previous example, however, the progress elements are automatically removed when the upload is completed.
|
||||
|
||||
```javascript
|
||||
var uploader = new ss.SimpleUpload({
|
||||
button: 'uploadButton',
|
||||
url: 'uploadHandler.php', // server side handler
|
||||
progressUrl: 'uploadProgress.php', // enables cross-browser progress support (more info below)
|
||||
responseType: 'json',
|
||||
name: 'uploadfile',
|
||||
multiple: true,
|
||||
allowedExtensions: ['jpg', 'jpeg', 'png', 'gif'], // for example, if we were uploading pics
|
||||
hoverClass: 'ui-state-hover',
|
||||
focusClass: 'ui-state-focus',
|
||||
disabledClass: 'ui-state-disabled',
|
||||
onSubmit: function(filename, extension) {
|
||||
// Create the elements of our progress bar
|
||||
var progress = document.createElement('div'), // container for progress bar
|
||||
bar = document.createElement('div'), // actual progress bar
|
||||
fileSize = document.createElement('div'), // container for upload file size
|
||||
wrapper = document.createElement('div'), // container for this progress bar
|
||||
progressBox = document.getElementById('progressBox'); // on page container for progress bars
|
||||
|
||||
// Assign each element its corresponding class
|
||||
progress.className = 'progress';
|
||||
bar.className = 'bar';
|
||||
fileSize.className = 'size';
|
||||
wrapper.className = 'wrapper';
|
||||
|
||||
// Assemble the progress bar and add it to the page
|
||||
progress.appendChild(bar);
|
||||
wrapper.innerHTML = '<div class="name">'+filename+'</div>'; // filename is passed to onSubmit()
|
||||
wrapper.appendChild(fileSize);
|
||||
wrapper.appendChild(progress);
|
||||
progressBox.appendChild(wrapper); // just an element on the page to hold the progress bars
|
||||
|
||||
// Assign roles to the elements of the progress bar
|
||||
this.setProgressBar(bar); // will serve as the actual progress bar
|
||||
this.setFileSizeBox(fileSize); // display file size beside progress bar
|
||||
this.setProgressContainer(wrapper); // designate the containing div to be removed after upload
|
||||
},
|
||||
|
||||
// Do something after finishing the upload
|
||||
// Note that the progress bar will be automatically removed upon completion because everything
|
||||
// is encased in the "wrapper", which was designated to be removed with setProgressContainer()
|
||||
onComplete: function(filename, response) {
|
||||
if (!response) {
|
||||
alert(filename + 'upload failed');
|
||||
return false;
|
||||
}
|
||||
// Stuff to do after finishing an upload...
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
For multiple file uploads, we use an additional function: `setProgressContainer(elem)`. This function designates an element to be removed from the DOM after the upload is completed.
|
||||
|
||||
In the example, the element set to be removed with `setProgressContainer()` is the outer container for the progress elements. As a result, progress bars will be removed from the DOM after each upload is completed.
|
||||
|
||||
### Cross-Browser Helper Functions ###
|
||||
|
||||
To ease the pain of supporting older browsers, the plugin includes a set of callback functions which allow specific behavior to be defined based on whether the user's browser supports XHR uploads/HTML5 File API:
|
||||
|
||||
<code>startXHR(filename, fileSize)</code> - Called prior to upload -- only in browsers that support XHR uploads<br />
|
||||
<code>endXHR(filename)</code> - Called after upload is completed -- only in browsers that support XHR uploads<br />
|
||||
<code>startNonXHR(filename)</code> - Called prior to upload -- only in browsers that <strong>do not</strong> support XHR uploads<br />
|
||||
<code>endNonXHR(filename)</code> - Called after upload is completed -- only in browsers that <strong>do not</strong> support XHR uploads<br />
|
||||
|
||||
A common use case is to show an upload progress bar in browsers that support the <code>progress</code> event while displaying an animated GIF in older browsers:
|
||||
|
||||
```javascript
|
||||
|
||||
var progress = document.getElementById('progress'), // progress bar
|
||||
loaderImg = document.getElementById('loaderImg'); // "loading" animated GIF
|
||||
|
||||
var uploader = new ss.SimpleUpload({
|
||||
button: 'uploadButton',
|
||||
url: 'uploadHandler.php', // server side handler
|
||||
responseType: 'json',
|
||||
name: 'uploadfile',
|
||||
hoverClass: 'ui-state-hover',
|
||||
focusClass: 'ui-state-focus',
|
||||
disabledClass: 'ui-state-disabled',
|
||||
startXHR: function(filename, size) {
|
||||
progress.style.display = 'inline-block'; // show progress bar
|
||||
this.setProgressBar(progress); // designate as progress bar
|
||||
},
|
||||
endXHR: function(filename) {
|
||||
progress.style.display = 'none'; // hide progress bar
|
||||
},
|
||||
startNonXHR: function(filename) {
|
||||
loaderImg.style.display = 'inline-block'; // show animated GIF
|
||||
},
|
||||
endNonXHR: function(filename) {
|
||||
loaderImg.style.display = 'none'; // hide animated GIF
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
Returning <code>false</code> from <code>startXHR()</code> and <code>startNonXHR()</code> will prevent the upload from starting, just as it does with <code>onSubmit()</code> and <code>onChange()</code>.
|
||||
|
||||
### Server-side file handling ###
|
||||
Files are uploaded by POST as either raw form data or regular multipart/form-data, depending on the browser.
|
||||
|
||||
### Using Uploader.php ###
|
||||
|
||||
<strong>Note:</strong> This PHP class is included only for convenience. <strong>It is not required to use PHP with Simple Ajax Uploader.</strong> The plugin is agnostic to server configuration, so use any language you prefer.
|
||||
|
||||
```php
|
||||
<?php
|
||||
require('Uploader.php');
|
||||
|
||||
$upload_dir = '/img_uploads/';
|
||||
$valid_extensions = array('gif', 'png', 'jpeg', 'jpg');
|
||||
|
||||
$Upload = new FileUpload('uploadfile');
|
||||
$result = $Upload->handleUpload($upload_dir, $valid_extensions);
|
||||
|
||||
if (!$result) {
|
||||
echo json_encode(array('success' => false, 'msg' => $Upload->getErrorMsg()));
|
||||
} else {
|
||||
echo json_encode(array('success' => true, 'file' => $Upload->getFileName()));
|
||||
}
|
||||
```
|
||||
|
||||
You can also save the uploaded file with a different name by setting the `newFileName` property:
|
||||
|
||||
```php
|
||||
$Upload = new FileUpload('uploadfile');
|
||||
$ext = $Upload->getExtension(); // Get the extension of the uploaded file
|
||||
$Upload->newFileName = 'customFileName.'.$ext;
|
||||
$result = $Upload->handleUpload($upload_dir, $valid_extensions);
|
||||
```
|
||||
|
||||
To access the newly uploaded file, use the `getSavedFile()` method to get the file's path after the upload is completed:
|
||||
```php
|
||||
$Upload = new FileUpload('uploadfile');
|
||||
$result = $Upload->handleUpload($upload_dir, $valid_extensions);
|
||||
|
||||
if ($result) {
|
||||
$path = $Upload->getSavedFile();
|
||||
$imgsize = getimagesize($path);
|
||||
// image resizing stuff...
|
||||
}
|
||||
```
|
||||
|
||||
### Passing Custom Headers ###
|
||||
|
||||
```javascript
|
||||
var uploader = new ss.SimpleUpload({
|
||||
customHeaders: {'Authorization': 'my-access-token'},
|
||||
...
|
||||
});
|
||||
|
||||
```
|
||||
|
||||
### Drag and Drop ###
|
||||
|
||||
Enable drag and drop uploading by passing an element to the `dropzone` option to serve as the drop zone:
|
||||
|
||||
```javascript
|
||||
var uploader = new ss.SimpleUpload({
|
||||
dropzone: 'dragbox', // ID of element to be the drop zone
|
||||
url: 'uploadHandler.php',
|
||||
name: 'uploadfile',
|
||||
responseType: 'json',
|
||||
onComplete: function(filename, response) {
|
||||
// do something with response...
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
### License ###
|
||||
Released under the MIT license.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,254 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Simple Ajax Uploader
|
||||
* Version 2.0
|
||||
* https://github.com/LPology/Simple-Ajax-Uploader
|
||||
*
|
||||
* Copyright 2012-2015 LPology, LLC
|
||||
* Released under the MIT license
|
||||
*
|
||||
* View the documentation for an example of how to use this class.
|
||||
*/
|
||||
|
||||
class FileUpload {
|
||||
private $fileName; // Filename of the uploaded file
|
||||
private $fileSize; // Size of uploaded file in bytes
|
||||
private $fileExtension; // File extension of uploaded file
|
||||
private $fileNameWithoutExt;
|
||||
private $savedFile; // Path to newly uploaded file (after upload completed)
|
||||
private $errorMsg; // Error message if handleUpload() returns false (use getErrorMsg() to retrieve)
|
||||
private $isXhr;
|
||||
public $uploadDir; // File upload directory (include trailing slash)
|
||||
public $allowedExtensions; // Array of permitted file extensions
|
||||
public $sizeLimit = 10485760; // Max file upload size in bytes (default 10MB)
|
||||
public $newFileName; // Optionally save uploaded files with a new name by setting this
|
||||
public $corsInputName = 'XHR_CORS_TARGETORIGIN';
|
||||
public $uploadName = 'uploadfile';
|
||||
|
||||
function __construct($uploadName = null) {
|
||||
if ($uploadName !== null) {
|
||||
$this->uploadName = $uploadName;
|
||||
}
|
||||
|
||||
if (isset($_FILES[$this->uploadName])) {
|
||||
$this->isXhr = false;
|
||||
|
||||
if ($_FILES[$this->uploadName]['error'] === UPLOAD_ERR_OK) {
|
||||
$this->fileName = $_FILES[$this->uploadName]['name'];
|
||||
$this->fileSize = $_FILES[$this->uploadName]['size'];
|
||||
|
||||
} else {
|
||||
$this->setErrorMsg($this->errorCodeToMsg($_FILES[$this->uploadName]['error']));
|
||||
}
|
||||
|
||||
} elseif (isset($_SERVER['HTTP_X_FILE_NAME']) || isset($_GET[$this->uploadName])) {
|
||||
$this->isXhr = true;
|
||||
|
||||
$this->fileName = isset($_SERVER['HTTP_X_FILE_NAME']) ?
|
||||
$_SERVER['HTTP_X_FILE_NAME'] : $_GET[$this->uploadName];
|
||||
|
||||
if (isset($_SERVER['CONTENT_LENGTH'])) {
|
||||
$this->fileSize = (int)$_SERVER['CONTENT_LENGTH'];
|
||||
|
||||
} else {
|
||||
throw new Exception('Content length is empty.');
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->fileName) {
|
||||
$pathinfo = pathinfo($this->fileName);
|
||||
|
||||
if (array_key_exists('extension', $pathinfo) &&
|
||||
array_key_exists('filename', $pathinfo))
|
||||
{
|
||||
$this->fileExtension = strtolower($pathinfo['extension']);
|
||||
$this->fileNameWithoutExt = $pathinfo['filename'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getFileName() {
|
||||
return $this->fileName;
|
||||
}
|
||||
|
||||
public function getFileSize() {
|
||||
return $this->fileSize;
|
||||
}
|
||||
|
||||
public function getExtension() {
|
||||
return $this->fileExtension;
|
||||
}
|
||||
|
||||
public function getErrorMsg() {
|
||||
return $this->errorMsg;
|
||||
}
|
||||
|
||||
public function getSavedFile() {
|
||||
return $this->savedFile;
|
||||
}
|
||||
|
||||
private function errorCodeToMsg($code) {
|
||||
switch($code) {
|
||||
case UPLOAD_ERR_INI_SIZE:
|
||||
$message = 'File size exceeds limit.';
|
||||
break;
|
||||
case UPLOAD_ERR_PARTIAL:
|
||||
$message = 'The uploaded file was only partially uploaded.';
|
||||
break;
|
||||
case UPLOAD_ERR_NO_FILE:
|
||||
$message = 'No file was uploaded.';
|
||||
break;
|
||||
case UPLOAD_ERR_NO_TMP_DIR:
|
||||
$message = 'Missing a temporary folder.';
|
||||
break;
|
||||
case UPLOAD_ERR_CANT_WRITE:
|
||||
$message = 'Failed to write file to disk.';
|
||||
break;
|
||||
case UPLOAD_ERR_EXTENSION:
|
||||
$message = 'File upload stopped by extension.';
|
||||
break;
|
||||
default:
|
||||
$message = 'Unknown upload error.';
|
||||
break;
|
||||
}
|
||||
return $message;
|
||||
}
|
||||
|
||||
private function checkExtension($ext, $allowedExtensions) {
|
||||
if (!is_array($allowedExtensions))
|
||||
return false;
|
||||
|
||||
if (!in_array(strtolower($ext), array_map('strtolower', $allowedExtensions)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function setErrorMsg($msg) {
|
||||
if (empty($this->errorMsg))
|
||||
$this->errorMsg = $msg;
|
||||
}
|
||||
|
||||
private function fixDir($dir) {
|
||||
if (empty($dir))
|
||||
return $dir;
|
||||
|
||||
$slash = DIRECTORY_SEPARATOR;
|
||||
$dir = str_replace('/', $slash, $dir);
|
||||
$dir = str_replace('\\', $slash, $dir);
|
||||
return substr($dir, -1) == $slash ? $dir : $dir . $slash;
|
||||
}
|
||||
|
||||
// escapeJS and jsMatcher are adapted from the Escaper component of
|
||||
// Zend Framework, Copyright (c) 2005-2013, Zend Technologies USA, Inc.
|
||||
// https://github.com/zendframework/zf2/tree/master/library/Zend/Escaper
|
||||
private function escapeJS($string) {
|
||||
return preg_replace_callback('/[^a-z0-9,\._]/iSu', $this->jsMatcher, $string);
|
||||
}
|
||||
|
||||
private function jsMatcher($matches) {
|
||||
$chr = $matches[0];
|
||||
|
||||
if (strlen($chr) == 1)
|
||||
return sprintf('\\x%02X', ord($chr));
|
||||
|
||||
if (function_exists('iconv'))
|
||||
$chr = iconv('UTF-16BE', 'UTF-8', $chr);
|
||||
|
||||
elseif (function_exists('mb_convert_encoding'))
|
||||
$chr = mb_convert_encoding($chr, 'UTF-8', 'UTF-16BE');
|
||||
|
||||
return sprintf('\\u%04s', strtoupper(bin2hex($chr)));
|
||||
}
|
||||
|
||||
public function corsResponse($data) {
|
||||
if (isset($_REQUEST[$this->corsInputName])) {
|
||||
$targetOrigin = $this->escapeJS($_REQUEST[$this->corsInputName]);
|
||||
$targetOrigin = htmlspecialchars($targetOrigin, ENT_QUOTES, 'UTF-8');
|
||||
return "<script>window.parent.postMessage('$data','$targetOrigin');</script>";
|
||||
}
|
||||
return $data;
|
||||
}
|
||||
|
||||
private function saveXhr($path) {
|
||||
if (false !== file_put_contents($path, fopen('php://input', 'r')))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private function saveForm($path) {
|
||||
if (move_uploaded_file($_FILES[$this->uploadName]['tmp_name'], $path))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private function save($path) {
|
||||
if (true === $this->isXhr)
|
||||
return $this->saveXhr($path);
|
||||
return $this->saveForm($path);
|
||||
}
|
||||
|
||||
public function handleUpload($uploadDir = null, $allowedExtensions = null) {
|
||||
if (!$this->fileName) {
|
||||
$this->setErrorMsg('Incorrect upload name or no file uploaded');
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->fileSize == 0) {
|
||||
$this->setErrorMsg('File is empty');
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->fileSize > $this->sizeLimit) {
|
||||
$this->setErrorMsg('File size exceeds limit');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($uploadDir))
|
||||
$this->uploadDir = $uploadDir;
|
||||
|
||||
$this->uploadDir = $this->fixDir($this->uploadDir);
|
||||
|
||||
if (!is_writable($this->uploadDir)) {
|
||||
$this->setErrorMsg('Upload directory is not writable');
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_array($allowedExtensions))
|
||||
$this->allowedExtensions = $allowedExtensions;
|
||||
|
||||
if (!empty($this->allowedExtensions)) {
|
||||
if (!$this->checkExtension($this->fileExtension, $this->allowedExtensions)) {
|
||||
$this->setErrorMsg('Invalid file type');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->savedFile = $this->uploadDir . $this->fileName;
|
||||
|
||||
if (!empty($this->newFileName)) {
|
||||
$this->fileName = $this->newFileName;
|
||||
$this->savedFile = $this->uploadDir . $this->fileName;
|
||||
|
||||
$this->fileNameWithoutExt = null;
|
||||
$this->fileExtension = null;
|
||||
|
||||
$pathinfo = pathinfo($this->fileName);
|
||||
|
||||
if (array_key_exists('filename', $pathinfo))
|
||||
$this->fileNameWithoutExt = $pathinfo['filename'];
|
||||
|
||||
if (array_key_exists('extension', $pathinfo))
|
||||
$this->fileExtension = strtolower($pathinfo['extension']);
|
||||
}
|
||||
|
||||
if (!$this->save($this->savedFile)) {
|
||||
$this->setErrorMsg('File could not be saved');
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
725
etc/apps/laragon/extras/assets/css/bootstrap.min.css
vendored
725
etc/apps/laragon/extras/assets/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -1,28 +0,0 @@
|
||||
.container {
|
||||
width: auto;
|
||||
max-width: 680px;
|
||||
padding: 0 15px;
|
||||
}
|
||||
|
||||
.progress {
|
||||
margin-bottom:0;
|
||||
margin-top:6px;
|
||||
margin-left:10px;
|
||||
}
|
||||
|
||||
.btn.focus {
|
||||
outline:thin dotted #333;
|
||||
outline:5px auto -webkit-focus-ring-color;
|
||||
outline-offset:-2px;
|
||||
}
|
||||
|
||||
.btn.hover {
|
||||
color:#ffffff;
|
||||
background-color:#3276b1;
|
||||
border-color:#285e8e;
|
||||
}
|
||||
|
||||
.highlight {
|
||||
background-color: yellow;
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Simple Ajax Uploader
|
||||
* Version 2.0
|
||||
* https://github.com/LPology/Simple-Ajax-Uploader
|
||||
*
|
||||
* Copyright 2012-2015 LPology, LLC
|
||||
* Released under the MIT license
|
||||
*
|
||||
*/
|
||||
|
||||
if (isset($_SERVER['HTTP_ORIGIN'])) {
|
||||
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
|
||||
header('Access-Control-Allow-Credentials: true');
|
||||
header('Access-Control-Max-Age: 86400'); // cache for 1 day
|
||||
}
|
||||
|
||||
// Access-Control headers are received during OPTIONS requests
|
||||
if (isset($_SERVER['REQUEST_METHOD'])) {
|
||||
|
||||
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
|
||||
|
||||
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
|
||||
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
||||
}
|
||||
|
||||
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
|
||||
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
require('Uploader.php');
|
||||
|
||||
// Directory where we're storing uploaded images
|
||||
// Remember to set correct permissions or it won't work
|
||||
$upload_dir = '../uploads';
|
||||
|
||||
$uploader = new FileUpload('uploadfile');
|
||||
$uploader->sizeLimit = 1024*1024*1024; // Max file upload size in bytes 1GB)
|
||||
|
||||
// Handle the upload
|
||||
$result = $uploader->handleUpload($upload_dir);
|
||||
|
||||
if (!$result) {
|
||||
exit(json_encode(array('success' => false, 'msg' => $uploader->getErrorMsg())));
|
||||
}
|
||||
|
||||
echo json_encode(array('success' => true));
|
||||
@@ -1,45 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Simple Ajax Uploader
|
||||
* Version 2.0
|
||||
* https://github.com/LPology/Simple-Ajax-Uploader
|
||||
*
|
||||
* Copyright 2012-2015 LPology, LLC
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Returns upload progress updates for browsers that don't support the HTML5 File API.
|
||||
* Falling back to this method allows for upload progress support across virtually all browsers.
|
||||
* Requires PHP 5.4+
|
||||
* Further documentation: http://php.net/manual/en/session.upload-progress.php
|
||||
*
|
||||
*/
|
||||
|
||||
session_start();
|
||||
|
||||
if (!isset($_POST[ini_get('session.upload_progress.name')])) {
|
||||
exit(json_encode(array('success' => false)));
|
||||
}
|
||||
|
||||
$key = ini_get('session.upload_progress.prefix') . $_POST[ini_get('session.upload_progress.name')];
|
||||
|
||||
if (!isset($_SESSION[$key])) {
|
||||
exit(json_encode(array('success' => false)));
|
||||
}
|
||||
|
||||
$progress = $_SESSION[$key];
|
||||
$pct = 0;
|
||||
$size = 0;
|
||||
|
||||
if (is_array($progress)) {
|
||||
|
||||
if (array_key_exists('bytes_processed', $progress) && array_key_exists('content_length', $progress)) {
|
||||
|
||||
if ($progress['content_length'] > 0) {
|
||||
$pct = round(($progress['bytes_processed'] / $progress['content_length']) * 100);
|
||||
$size = round($progress['content_length'] / 1024);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode(array('success' => true, 'pct' => $pct, 'size' => $size));
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Simple Ajax Uploader
|
||||
* Version 2.0
|
||||
* https://github.com/LPology/Simple-Ajax-Uploader
|
||||
*
|
||||
* Copyright 2012-2015 LPology, LLC
|
||||
* Released under the MIT license
|
||||
*
|
||||
* Returns upload progress updates for browsers that don't support the HTML5 File API.
|
||||
* Falling back to this method allows for upload progress support across virtually all browsers.
|
||||
*
|
||||
*/
|
||||
|
||||
// This "if" statement is only necessary for CORS uploads -- if you're
|
||||
// only doing same-domain uploads then you can delete it if you want
|
||||
if (isset($_SERVER['HTTP_ORIGIN'])) {
|
||||
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
|
||||
header('Access-Control-Allow-Credentials: true');
|
||||
header('Access-Control-Max-Age: 86400'); // cache for 1 day
|
||||
}
|
||||
|
||||
if (isset($_REQUEST['progresskey'])) {
|
||||
$status = apc_fetch('upload_'.$_REQUEST['progresskey']);
|
||||
} else {
|
||||
exit(json_encode(array('success' => false)));
|
||||
}
|
||||
|
||||
$pct = 0;
|
||||
$size = 0;
|
||||
|
||||
if (is_array($status)) {
|
||||
|
||||
if (array_key_exists('total', $status) && array_key_exists('current', $status)) {
|
||||
|
||||
if ($status['total'] > 0) {
|
||||
$pct = round(($status['current'] / $status['total']) * 100);
|
||||
$size = round($status['total'] / 1024);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode(array('success' => true, 'pct' => $pct, 'size' => $size));
|
||||
@@ -1,154 +0,0 @@
|
||||
<?php
|
||||
function formatLink($file) {
|
||||
if (isset($_SERVER['HTTPS']) &&
|
||||
($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
|
||||
isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
|
||||
$_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
|
||||
$protocol = 'https';
|
||||
} else {
|
||||
$protocol = 'http';
|
||||
}
|
||||
$link = sprintf('%s://%s/laragon/uploads/%s', $protocol, $_SERVER['HTTP_HOST'], $file);
|
||||
return sprintf('<a href="%s" target="_blank">%s</a>', $link, $link);
|
||||
}
|
||||
function listFiles() {
|
||||
$upload_dir = dirname(__FILE__).'\uploads';
|
||||
echo sprintf('<div>Files locate at: <b>%s</b></div>', $upload_dir);
|
||||
if ($handle = opendir($upload_dir)) {
|
||||
|
||||
while (false !== ($entry = readdir($handle))) {
|
||||
if ($entry != "." && $entry != "..") {
|
||||
echo '<div>'.formatLink($entry).'</div>';
|
||||
}
|
||||
}
|
||||
|
||||
closedir($handle);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Uploader</title>
|
||||
<link href="extras/assets/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="extras/assets/css/styles.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div class="container">
|
||||
<div class="row" style="padding-top:10px;">
|
||||
<div class="col-xs-2">
|
||||
<button id="uploadBtn" class="btn btn-large btn-primary">Choose Files</button>
|
||||
</div>
|
||||
<div class="col-xs-10">
|
||||
<div id="progressOuter" class="progress progress-striped active" style="display:none;">
|
||||
<div id="progressBar" class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="padding-top:10px;">
|
||||
<div class="col-xs-10">
|
||||
<div id="msgBox">
|
||||
</div>
|
||||
<div id="uploadedFiles">
|
||||
</div>
|
||||
<p>
|
||||
<hr />
|
||||
<div>
|
||||
<small>
|
||||
<div><u>Tip</u>: Hold Shift if you want to upload multiple files.</div>
|
||||
<div>If you want to share over the Internet, just run:</div>
|
||||
<div><b><i>ngrok http 80</i></b></div>
|
||||
</small>
|
||||
</div>
|
||||
<hr />
|
||||
<div id="listFiles">
|
||||
<?php
|
||||
listFiles();
|
||||
|
||||
//$upload_dir = dirname(__FILE__).'\uploads';
|
||||
//echo $upload_dir;
|
||||
//echo '<a href="http://'.$_SERVER['HTTP_HOST'].'/laragon/uploads/" target="_blank">'.$_SERVER['HTTP_HOST'].'</a>';
|
||||
?>
|
||||
</div>
|
||||
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="extras/SimpleAjaxUploader.min.js"></script>
|
||||
<script>
|
||||
function escapeTags( str ) {
|
||||
return String( str )
|
||||
.replace( /&/g, '&' )
|
||||
.replace( /"/g, '"' )
|
||||
.replace( /'/g, ''' )
|
||||
.replace( /</g, '<' )
|
||||
.replace( />/g, '>' );
|
||||
}
|
||||
|
||||
function replaceAll(str, find, replace) {
|
||||
return str.replace(new RegExp(find, 'g'), replace);
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
|
||||
var btn = document.getElementById('uploadBtn'),
|
||||
progressBar = document.getElementById('progressBar'),
|
||||
progressOuter = document.getElementById('progressOuter'),
|
||||
msgBox = document.getElementById('msgBox');
|
||||
listFiles = document.getElementById('listFiles');
|
||||
theLink = '<?php echo formatLink('{{FILE}}'); ?>';
|
||||
|
||||
var uploader = new ss.SimpleUpload({
|
||||
button: btn,
|
||||
url: 'extras/file_upload.php',
|
||||
name: 'uploadfile',
|
||||
hoverClass: 'hover',
|
||||
multiple: true,
|
||||
focusClass: 'focus',
|
||||
responseType: 'json',
|
||||
startXHR: function() {
|
||||
progressOuter.style.display = 'block'; // make progress bar visible
|
||||
this.setProgressBar( progressBar );
|
||||
},
|
||||
onSubmit: function() {
|
||||
msgBox.innerHTML = ''; // empty the message box
|
||||
btn.innerHTML = 'Uploading...'; // change button text to "Uploading..."
|
||||
},
|
||||
onComplete: function( filename, response ) {
|
||||
btn.innerHTML = 'Choose Files';
|
||||
progressOuter.style.display = 'none'; // hide progress bar when upload is completed
|
||||
|
||||
if ( !response ) {
|
||||
msgBox.innerHTML = 'Unable to upload file';
|
||||
return;
|
||||
}
|
||||
|
||||
if ( response.success === true ) {
|
||||
msgBox.innerHTML = '<strong>' + escapeTags( filename ) + '</strong>' + ' successfully uploaded.';
|
||||
uploadedFiles.innerHTML = '<div class="highlight">' + replaceAll(theLink, '{{FILE}}', filename) + '</div>' + uploadedFiles.innerHTML ;
|
||||
|
||||
} else {
|
||||
if ( response.msg ) {
|
||||
msgBox.innerHTML = escapeTags( response.msg );
|
||||
|
||||
} else {
|
||||
msgBox.innerHTML = 'An error occurred and the upload failed.';
|
||||
}
|
||||
}
|
||||
},
|
||||
onError: function() {
|
||||
progressOuter.style.display = 'none';
|
||||
msgBox.innerHTML = 'Unable to upload file';
|
||||
}
|
||||
});
|
||||
};
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1 +0,0 @@
|
||||
Antony Dovgal, Mikael Johansson
|
||||
@@ -1,68 +0,0 @@
|
||||
--------------------------------------------------------------------
|
||||
The PHP License, Version 3.0
|
||||
Copyright (c) 1999 - 2005 The PHP Group. All rights reserved.
|
||||
--------------------------------------------------------------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, is permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
3. The name "PHP" must not be used to endorse or promote products
|
||||
derived from this software without prior written permission. For
|
||||
written permission, please contact group@php.net.
|
||||
|
||||
4. Products derived from this software may not be called "PHP", nor
|
||||
may "PHP" appear in their name, without prior written permission
|
||||
from group@php.net. You may indicate that your software works in
|
||||
conjunction with PHP by saying "Foo for PHP" instead of calling
|
||||
it "PHP Foo" or "phpfoo"
|
||||
|
||||
5. The PHP Group may publish revised and/or new versions of the
|
||||
license from time to time. Each version will be given a
|
||||
distinguishing version number.
|
||||
Once covered code has been published under a particular version
|
||||
of the license, you may always continue to use it under the terms
|
||||
of that version. You may also choose to use such covered code
|
||||
under the terms of any subsequent version of the license
|
||||
published by the PHP Group. No one other than the PHP Group has
|
||||
the right to modify the terms applicable to covered code created
|
||||
under this License.
|
||||
|
||||
6. Redistributions of any form whatsoever must retain the following
|
||||
acknowledgment:
|
||||
"This product includes PHP, freely available from
|
||||
<http://www.php.net/>".
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
|
||||
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
|
||||
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
--------------------------------------------------------------------
|
||||
|
||||
This software consists of voluntary contributions made by many
|
||||
individuals on behalf of the PHP Group.
|
||||
|
||||
The PHP Group can be contacted via Email at group@php.net.
|
||||
|
||||
For more information on the PHP Group and the PHP project,
|
||||
please see <http://www.php.net>.
|
||||
|
||||
This product includes the Zend Engine, freely available at
|
||||
<http://www.zend.com>.
|
||||
@@ -1,149 +0,0 @@
|
||||
memcached module for PHP
|
||||
------------------------
|
||||
This module requires zlib library, used for on-the-fly data (de)compression.
|
||||
Also, you'll need memcached to use it =)
|
||||
|
||||
The memcached website is here:
|
||||
http://www.danga.com/memcached/
|
||||
|
||||
You will probably need libevent to install memcached:
|
||||
You can download it here: http://www.monkey.org/~provos/libevent/
|
||||
|
||||
How to run tests:
|
||||
1. sh tests/memcache.sh
|
||||
2. TEST_PHP_EXECUTABLE=/usr/local/bin/php php -dextension=modules/memcache.so run-tests.php -d extension=modules/memcache.so
|
||||
|
||||
|
||||
New API in 3.0
|
||||
------------------------
|
||||
|
||||
Version 3 introduces a new class "MemcachePool" which implements the new API, the
|
||||
old class "Memcache" is still retained (but is deprecated) with the same interface
|
||||
for backwards compatibility. Please note that you need a new memcached version to
|
||||
use the CAS, default value to increment/decrement, append and prepend, and binary
|
||||
protocol features.
|
||||
|
||||
New INI directives are available to allow control over protocol, redundancy and hash
|
||||
strategy selection. These are
|
||||
|
||||
# The binary protocol results in less traffic and is more efficient
|
||||
# for the client and server to generate/parse
|
||||
|
||||
memcache.protocol = {ascii, binary} # default ascii
|
||||
|
||||
# When enabled the client sends requests to N servers in parallel, resulting in
|
||||
# a somewhat crude reduncancy or mirroring, suitable when used as a session
|
||||
# storage.
|
||||
#
|
||||
# If data integrity is of greater importance a real replicating memcached
|
||||
# backend such as "repcached" (http://sourceforge.net/projects/repcached/) is
|
||||
# recommended
|
||||
|
||||
memcache.redundancy = <int> # default 1
|
||||
memcache.session_redundancy = <int> # default 2
|
||||
|
||||
# Hash strategy and function selection. The consistent hashing strategy
|
||||
# is now the default as it allows servers to be added and removed from
|
||||
# the pool without resulting in all or most keys being re-mapped to
|
||||
# other server (ie. voiding the cache)
|
||||
|
||||
memcache.hash_strategy = {standard, consistent} # default consistent
|
||||
memcache.hash_function = {crc32, fnv} # default crc32
|
||||
|
||||
# Compression is enabled by default, the threshold which control the minimum
|
||||
# string length which triggers compresssion can be changed as
|
||||
|
||||
memcache.compress_threshold = <int> # default 20000
|
||||
|
||||
|
||||
The directives are used by the MemcachePool constructor so you can instantiate
|
||||
several pools with different settings by using ini_set() creativly. For example
|
||||
|
||||
ini_set('memcache.protocol', 'binary');
|
||||
|
||||
$binarypool = new MemcachePool();
|
||||
$binarypool->addServer(...)
|
||||
|
||||
ini_set('memcache.protocol', 'ascii');
|
||||
ini_set('memcache.redundancy', '2');
|
||||
|
||||
$redundantpool = new MemcachePool();
|
||||
$redundantpool->addServer(...)
|
||||
|
||||
ini_set('memcache.redundancy', '1');
|
||||
|
||||
|
||||
The new interface looks like
|
||||
|
||||
class MemcachePool() {
|
||||
bool connect(string host, int tcp_port = 11211, int udp_port = 0, bool persistent = true, int weight = 1, int timeout = 1, int retry_interval = 15)
|
||||
bool addServer(string host, int tcp_port = 11211, int udp_port = 0, bool persistent = true, int weight = 1, int timeout = 1, int retry_interval = 15, bool status = true)
|
||||
bool setServerParams(string host, int tcp_port = 11211, int timeout = 1, int retry_interval = 15, bool status = true)
|
||||
|
||||
/**
|
||||
* Supports fetching flags and CAS values
|
||||
*/
|
||||
mixed get(mixed key, mixed &flags = null, mixed &cas = null)
|
||||
|
||||
/**
|
||||
* Supports multi-set, for example
|
||||
* $memcache->set(array('key1' => 'val1', 'key2' => 'val1'), null, 0, 60)
|
||||
*/
|
||||
bool add(mixed key, mixed var = null, int flag = 0, int exptime = 0)
|
||||
bool set(mixed key, mixed var = null, int flag = 0, int exptime = 0)
|
||||
bool replace(mixed key, mixed var = null, int flag = 0, int exptime = 0)
|
||||
|
||||
/**
|
||||
* Compare-and-Swap, uses the CAS param from MemcachePool::get()
|
||||
*/
|
||||
bool cas(mixed key, mixed var = null, int flag = 0, int exptime = 0, int cas = 0)
|
||||
|
||||
/**
|
||||
* Prepends/appends a value to an existing one
|
||||
*/
|
||||
bool append(mixed key, mixed var = null, int flag = 0, int exptime = 0)
|
||||
bool prepend(mixed key, mixed var = null, int flag = 0, int exptime = 0)
|
||||
|
||||
/**
|
||||
* Supports multi-key operations, for example
|
||||
* $memcache->delete(array('key1', 'key2'))
|
||||
*/
|
||||
bool delete(mixed key, int exptime = 0)
|
||||
|
||||
/**
|
||||
* Supports multi-key operations, for example
|
||||
* $memcache->increment(array('key1', 'key2'), 1, 0, 0)
|
||||
*
|
||||
* The new defval (default value) and exptime (expiration time) are used
|
||||
* if the key doesn't already exist. They must be supplied (even if 0) for
|
||||
* this to be enabled.
|
||||
*
|
||||
* Returns an integer with the new value if key is a string
|
||||
* Returns an array of integers if the key is an array
|
||||
*/
|
||||
mixed increment(mixed key, int value = 1, int defval = 0, int exptime = 0)
|
||||
mixed decrement(mixed key, int value = 1, int defval = 0, int exptime = 0)
|
||||
|
||||
/**
|
||||
* Assigns a pool-specific failure callback which will be called when
|
||||
* a request fails. May be null in order to disable callbacks. The callback
|
||||
* receive arguments like
|
||||
*
|
||||
* function mycallback($host, $tcp_port, $udp_port, $error, $errnum)
|
||||
*
|
||||
* Where $host and $error are strings or null, the other params are integers.
|
||||
*/
|
||||
bool setFailureCallback(function callback)
|
||||
|
||||
/**
|
||||
* Locates the server a given would be hashed to
|
||||
*
|
||||
* Returns a string "hostname:port" on success
|
||||
* Returns false on failure such as invalid key
|
||||
*/
|
||||
string findServer(string key)
|
||||
}
|
||||
|
||||
|
||||
Maintainers:
|
||||
Herman J. Radtke III hradtke at php dot net
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
$memcache = memcache_connect('localhost', 11211);
|
||||
|
||||
if ($memcache) {
|
||||
$memcache->set("str_key", "String to store in memcached");
|
||||
$memcache->set("num_key", 123);
|
||||
|
||||
$object = new StdClass;
|
||||
$object->attribute = 'test';
|
||||
$memcache->set("obj_key", $object);
|
||||
|
||||
$array = Array('assoc'=>123, 345, 567);
|
||||
$memcache->set("arr_key", $array);
|
||||
|
||||
var_dump($memcache->get('str_key'));
|
||||
var_dump($memcache->get('num_key'));
|
||||
var_dump($memcache->get('obj_key'));
|
||||
}
|
||||
else {
|
||||
echo "Connection to memcached failed";
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -1,900 +0,0 @@
|
||||
<?php
|
||||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| Copyright (c) 1997-2004 The PHP Group |
|
||||
+----------------------------------------------------------------------+
|
||||
| This source file is subject to version 3.0 of the PHP license, |
|
||||
| that is bundled with this package in the file LICENSE, and is |
|
||||
| available through the world-wide-web at the following url: |
|
||||
| http://www.php.net/license/3_0.txt. |
|
||||
| If you did not receive a copy of the PHP license and are unable to |
|
||||
| obtain it through the world-wide-web, please send a note to |
|
||||
| license@php.net so we can mail you a copy immediately. |
|
||||
+----------------------------------------------------------------------+
|
||||
| Author: Harun Yayli <harunyayli at gmail.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
$VERSION='$Id: memcache.php 326707 2012-07-19 19:02:42Z ab $';
|
||||
|
||||
define('ADMIN_USERNAME','mem'); // Admin Username
|
||||
define('ADMIN_PASSWORD','1'); // Admin Password
|
||||
define('DATE_FORMAT','Y/m/d H:i:s');
|
||||
define('GRAPH_SIZE',200);
|
||||
define('MAX_ITEM_DUMP',50);
|
||||
|
||||
$MEMCACHE_SERVERS[] = 'localhost:11211'; // add more as an array
|
||||
//$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array
|
||||
|
||||
|
||||
////////// END OF DEFAULT CONFIG AREA /////////////////////////////////////////////////////////////
|
||||
|
||||
///////////////// Password protect ////////////////////////////////////////////////////////////////
|
||||
if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) ||
|
||||
$_SERVER['PHP_AUTH_USER'] != ADMIN_USERNAME ||$_SERVER['PHP_AUTH_PW'] != ADMIN_PASSWORD) {
|
||||
Header("WWW-Authenticate: Basic realm=\"Memcache Login (Username: ".ADMIN_USERNAME."/Password: ".ADMIN_PASSWORD.")\"");
|
||||
Header("HTTP/1.0 401 Unauthorized");
|
||||
|
||||
echo <<<EOB
|
||||
<html><body>
|
||||
<h1>Rejected!</h1>
|
||||
<big>Wrong Username or Password!</big>
|
||||
</body></html>
|
||||
EOB;
|
||||
exit;
|
||||
}
|
||||
|
||||
///////////MEMCACHE FUNCTIONS /////////////////////////////////////////////////////////////////////
|
||||
|
||||
function get_host_port_from_server($server){
|
||||
$values = explode(':', $server);
|
||||
if (($values[0] == 'unix') && (!is_numeric( $values[1]))) {
|
||||
return array($server, 0);
|
||||
}
|
||||
else {
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
||||
function sendMemcacheCommands($command){
|
||||
global $MEMCACHE_SERVERS;
|
||||
$result = array();
|
||||
|
||||
foreach($MEMCACHE_SERVERS as $server){
|
||||
$strs = get_host_port_from_server($server);
|
||||
$host = $strs[0];
|
||||
$port = $strs[1];
|
||||
$result[$server] = sendMemcacheCommand($host,$port,$command);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
function sendMemcacheCommand($server,$port,$command){
|
||||
|
||||
$s = @fsockopen($server,$port);
|
||||
if (!$s){
|
||||
die("Cant connect to:".$server.':'.$port);
|
||||
}
|
||||
|
||||
fwrite($s, $command."\r\n");
|
||||
|
||||
$buf='';
|
||||
while ((!feof($s))) {
|
||||
$buf .= fgets($s, 256);
|
||||
if (strpos($buf,"END\r\n")!==false){ // stat says end
|
||||
break;
|
||||
}
|
||||
if (strpos($buf,"DELETED\r\n")!==false || strpos($buf,"NOT_FOUND\r\n")!==false){ // delete says these
|
||||
break;
|
||||
}
|
||||
if (strpos($buf,"OK\r\n")!==false){ // flush_all says ok
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose($s);
|
||||
return parseMemcacheResults($buf);
|
||||
}
|
||||
function parseMemcacheResults($str){
|
||||
|
||||
$res = array();
|
||||
$lines = explode("\r\n",$str);
|
||||
$cnt = count($lines);
|
||||
for($i=0; $i< $cnt; $i++){
|
||||
$line = $lines[$i];
|
||||
$l = explode(' ',$line,3);
|
||||
if (count($l)==3){
|
||||
$res[$l[0]][$l[1]]=$l[2];
|
||||
if ($l[0]=='VALUE'){ // next line is the value
|
||||
$res[$l[0]][$l[1]] = array();
|
||||
list ($flag,$size)=explode(' ',$l[2]);
|
||||
$res[$l[0]][$l[1]]['stat']=array('flag'=>$flag,'size'=>$size);
|
||||
$res[$l[0]][$l[1]]['value']=$lines[++$i];
|
||||
}
|
||||
}elseif($line=='DELETED' || $line=='NOT_FOUND' || $line=='OK'){
|
||||
return $line;
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
|
||||
}
|
||||
|
||||
function dumpCacheSlab($server,$slabId,$limit){
|
||||
list($host,$port) = get_host_port_from_server($server);
|
||||
$resp = sendMemcacheCommand($host,$port,'stats cachedump '.$slabId.' '.$limit);
|
||||
|
||||
return $resp;
|
||||
|
||||
}
|
||||
|
||||
function flushServer($server){
|
||||
list($host,$port) = get_host_port_from_server($server);
|
||||
$resp = sendMemcacheCommand($host,$port,'flush_all');
|
||||
return $resp;
|
||||
}
|
||||
function getCacheItems(){
|
||||
$items = sendMemcacheCommands('stats items');
|
||||
$serverItems = array();
|
||||
$totalItems = array();
|
||||
foreach ($items as $server=>$itemlist){
|
||||
$serverItems[$server] = array();
|
||||
$totalItems[$server]=0;
|
||||
if (!isset($itemlist['STAT'])){
|
||||
continue;
|
||||
}
|
||||
|
||||
$iteminfo = $itemlist['STAT'];
|
||||
|
||||
foreach($iteminfo as $keyinfo=>$value){
|
||||
if (preg_match('/items\:(\d+?)\:(.+?)$/',$keyinfo,$matches)){
|
||||
$serverItems[$server][$matches[1]][$matches[2]] = $value;
|
||||
if ($matches[2]=='number'){
|
||||
$totalItems[$server] +=$value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return array('items'=>$serverItems,'counts'=>$totalItems);
|
||||
}
|
||||
function getMemcacheStats($total=true){
|
||||
$resp = sendMemcacheCommands('stats');
|
||||
if ($total){
|
||||
$res = array();
|
||||
foreach($resp as $server=>$r){
|
||||
foreach($r['STAT'] as $key=>$row){
|
||||
if (!isset($res[$key])){
|
||||
$res[$key]=null;
|
||||
}
|
||||
switch ($key){
|
||||
case 'pid':
|
||||
$res['pid'][$server]=$row;
|
||||
break;
|
||||
case 'uptime':
|
||||
$res['uptime'][$server]=$row;
|
||||
break;
|
||||
case 'time':
|
||||
$res['time'][$server]=$row;
|
||||
break;
|
||||
case 'version':
|
||||
$res['version'][$server]=$row;
|
||||
break;
|
||||
case 'pointer_size':
|
||||
$res['pointer_size'][$server]=$row;
|
||||
break;
|
||||
case 'rusage_user':
|
||||
$res['rusage_user'][$server]=$row;
|
||||
break;
|
||||
case 'rusage_system':
|
||||
$res['rusage_system'][$server]=$row;
|
||||
break;
|
||||
case 'curr_items':
|
||||
$res['curr_items']+=$row;
|
||||
break;
|
||||
case 'total_items':
|
||||
$res['total_items']+=$row;
|
||||
break;
|
||||
case 'bytes':
|
||||
$res['bytes']+=$row;
|
||||
break;
|
||||
case 'curr_connections':
|
||||
$res['curr_connections']+=$row;
|
||||
break;
|
||||
case 'total_connections':
|
||||
$res['total_connections']+=$row;
|
||||
break;
|
||||
case 'connection_structures':
|
||||
$res['connection_structures']+=$row;
|
||||
break;
|
||||
case 'cmd_get':
|
||||
$res['cmd_get']+=$row;
|
||||
break;
|
||||
case 'cmd_set':
|
||||
$res['cmd_set']+=$row;
|
||||
break;
|
||||
case 'get_hits':
|
||||
$res['get_hits']+=$row;
|
||||
break;
|
||||
case 'get_misses':
|
||||
$res['get_misses']+=$row;
|
||||
break;
|
||||
case 'evictions':
|
||||
$res['evictions']+=$row;
|
||||
break;
|
||||
case 'bytes_read':
|
||||
$res['bytes_read']+=$row;
|
||||
break;
|
||||
case 'bytes_written':
|
||||
$res['bytes_written']+=$row;
|
||||
break;
|
||||
case 'limit_maxbytes':
|
||||
$res['limit_maxbytes']+=$row;
|
||||
break;
|
||||
case 'threads':
|
||||
$res['rusage_system'][$server]=$row;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
return $resp;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
|
||||
//
|
||||
// don't cache this page
|
||||
//
|
||||
header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
|
||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
||||
header("Pragma: no-cache"); // HTTP/1.0
|
||||
|
||||
function duration($ts) {
|
||||
global $time;
|
||||
$years = (int)((($time - $ts)/(7*86400))/52.177457);
|
||||
$rem = (int)(($time-$ts)-($years * 52.177457 * 7 * 86400));
|
||||
$weeks = (int)(($rem)/(7*86400));
|
||||
$days = (int)(($rem)/86400) - $weeks*7;
|
||||
$hours = (int)(($rem)/3600) - $days*24 - $weeks*7*24;
|
||||
$mins = (int)(($rem)/60) - $hours*60 - $days*24*60 - $weeks*7*24*60;
|
||||
$str = '';
|
||||
if($years==1) $str .= "$years year, ";
|
||||
if($years>1) $str .= "$years years, ";
|
||||
if($weeks==1) $str .= "$weeks week, ";
|
||||
if($weeks>1) $str .= "$weeks weeks, ";
|
||||
if($days==1) $str .= "$days day,";
|
||||
if($days>1) $str .= "$days days,";
|
||||
if($hours == 1) $str .= " $hours hour and";
|
||||
if($hours>1) $str .= " $hours hours and";
|
||||
if($mins == 1) $str .= " 1 minute";
|
||||
else $str .= " $mins minutes";
|
||||
return $str;
|
||||
}
|
||||
|
||||
// create graphics
|
||||
//
|
||||
function graphics_avail() {
|
||||
return extension_loaded('gd');
|
||||
}
|
||||
|
||||
function bsize($s) {
|
||||
foreach (array('','K','M','G') as $i => $k) {
|
||||
if ($s < 1024) break;
|
||||
$s/=1024;
|
||||
}
|
||||
return sprintf("%5.1f %sBytes",$s,$k);
|
||||
}
|
||||
|
||||
// create menu entry
|
||||
function menu_entry($ob,$title) {
|
||||
global $PHP_SELF;
|
||||
if ($ob==$_GET['op']){
|
||||
return "<li><a class=\"child_active\" href=\"$PHP_SELF&op=$ob\">$title</a></li>";
|
||||
}
|
||||
return "<li><a class=\"active\" href=\"$PHP_SELF&op=$ob\">$title</a></li>";
|
||||
}
|
||||
|
||||
function getHeader(){
|
||||
$header = <<<EOB
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
||||
<html>
|
||||
<head><title>MEMCACHE INFO</title>
|
||||
<style type="text/css"><!--
|
||||
body { background:white; font-size:100.01%; margin:0; padding:0; }
|
||||
body,p,td,th,input,submit { font-size:0.8em;font-family:arial,helvetica,sans-serif; }
|
||||
* html body {font-size:0.8em}
|
||||
* html p {font-size:0.8em}
|
||||
* html td {font-size:0.8em}
|
||||
* html th {font-size:0.8em}
|
||||
* html input {font-size:0.8em}
|
||||
* html submit {font-size:0.8em}
|
||||
td { vertical-align:top }
|
||||
a { color:black; font-weight:none; text-decoration:none; }
|
||||
a:hover { text-decoration:underline; }
|
||||
div.content { padding:1em 1em 1em 1em; position:absolute; width:97%; z-index:100; }
|
||||
|
||||
h1.memcache { background:rgb(153,153,204); margin:0; padding:0.5em 1em 0.5em 1em; }
|
||||
* html h1.memcache { margin-bottom:-7px; }
|
||||
h1.memcache a:hover { text-decoration:none; color:rgb(90,90,90); }
|
||||
h1.memcache span.logo {
|
||||
background:rgb(119,123,180);
|
||||
color:black;
|
||||
border-right: solid black 1px;
|
||||
border-bottom: solid black 1px;
|
||||
font-style:italic;
|
||||
font-size:1em;
|
||||
padding-left:1.2em;
|
||||
padding-right:1.2em;
|
||||
text-align:right;
|
||||
display:block;
|
||||
width:130px;
|
||||
}
|
||||
h1.memcache span.logo span.name { color:white; font-size:0.7em; padding:0 0.8em 0 2em; }
|
||||
h1.memcache span.nameinfo { color:white; display:inline; font-size:0.4em; margin-left: 3em; }
|
||||
h1.memcache div.copy { color:black; font-size:0.4em; position:absolute; right:1em; }
|
||||
hr.memcache {
|
||||
background:white;
|
||||
border-bottom:solid rgb(102,102,153) 1px;
|
||||
border-style:none;
|
||||
border-top:solid rgb(102,102,153) 10px;
|
||||
height:12px;
|
||||
margin:0;
|
||||
margin-top:1px;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
ol,menu { margin:1em 0 0 0; padding:0.2em; margin-left:1em;}
|
||||
ol.menu li { display:inline; margin-right:0.7em; list-style:none; font-size:85%}
|
||||
ol.menu a {
|
||||
background:rgb(153,153,204);
|
||||
border:solid rgb(102,102,153) 2px;
|
||||
color:white;
|
||||
font-weight:bold;
|
||||
margin-right:0em;
|
||||
padding:0.1em 0.5em 0.1em 0.5em;
|
||||
text-decoration:none;
|
||||
margin-left: 5px;
|
||||
}
|
||||
ol.menu a.child_active {
|
||||
background:rgb(153,153,204);
|
||||
border:solid rgb(102,102,153) 2px;
|
||||
color:white;
|
||||
font-weight:bold;
|
||||
margin-right:0em;
|
||||
padding:0.1em 0.5em 0.1em 0.5em;
|
||||
text-decoration:none;
|
||||
border-left: solid black 5px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
ol.menu span.active {
|
||||
background:rgb(153,153,204);
|
||||
border:solid rgb(102,102,153) 2px;
|
||||
color:black;
|
||||
font-weight:bold;
|
||||
margin-right:0em;
|
||||
padding:0.1em 0.5em 0.1em 0.5em;
|
||||
text-decoration:none;
|
||||
border-left: solid black 5px;
|
||||
}
|
||||
ol.menu span.inactive {
|
||||
background:rgb(193,193,244);
|
||||
border:solid rgb(182,182,233) 2px;
|
||||
color:white;
|
||||
font-weight:bold;
|
||||
margin-right:0em;
|
||||
padding:0.1em 0.5em 0.1em 0.5em;
|
||||
text-decoration:none;
|
||||
margin-left: 5px;
|
||||
}
|
||||
ol.menu a:hover {
|
||||
background:rgb(193,193,244);
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
|
||||
div.info {
|
||||
background:rgb(204,204,204);
|
||||
border:solid rgb(204,204,204) 1px;
|
||||
margin-bottom:1em;
|
||||
}
|
||||
div.info h2 {
|
||||
background:rgb(204,204,204);
|
||||
color:black;
|
||||
font-size:1em;
|
||||
margin:0;
|
||||
padding:0.1em 1em 0.1em 1em;
|
||||
}
|
||||
div.info table {
|
||||
border:solid rgb(204,204,204) 1px;
|
||||
border-spacing:0;
|
||||
width:100%;
|
||||
}
|
||||
div.info table th {
|
||||
background:rgb(204,204,204);
|
||||
color:white;
|
||||
margin:0;
|
||||
padding:0.1em 1em 0.1em 1em;
|
||||
}
|
||||
div.info table th a.sortable { color:black; }
|
||||
div.info table tr.tr-0 { background:rgb(238,238,238); }
|
||||
div.info table tr.tr-1 { background:rgb(221,221,221); }
|
||||
div.info table td { padding:0.3em 1em 0.3em 1em; }
|
||||
div.info table td.td-0 { border-right:solid rgb(102,102,153) 1px; white-space:nowrap; }
|
||||
div.info table td.td-n { border-right:solid rgb(102,102,153) 1px; }
|
||||
div.info table td h3 {
|
||||
color:black;
|
||||
font-size:1.1em;
|
||||
margin-left:-0.3em;
|
||||
}
|
||||
.td-0 a , .td-n a, .tr-0 a , tr-1 a {
|
||||
text-decoration:underline;
|
||||
}
|
||||
div.graph { margin-bottom:1em }
|
||||
div.graph h2 { background:rgb(204,204,204);; color:black; font-size:1em; margin:0; padding:0.1em 1em 0.1em 1em; }
|
||||
div.graph table { border:solid rgb(204,204,204) 1px; color:black; font-weight:normal; width:100%; }
|
||||
div.graph table td.td-0 { background:rgb(238,238,238); }
|
||||
div.graph table td.td-1 { background:rgb(221,221,221); }
|
||||
div.graph table td { padding:0.2em 1em 0.4em 1em; }
|
||||
|
||||
div.div1,div.div2 { margin-bottom:1em; width:35em; }
|
||||
div.div3 { position:absolute; left:40em; top:1em; width:580px; }
|
||||
//div.div3 { position:absolute; left:37em; top:1em; right:1em; }
|
||||
|
||||
div.sorting { margin:1.5em 0em 1.5em 2em }
|
||||
.center { text-align:center }
|
||||
.aright { position:absolute;right:1em }
|
||||
.right { text-align:right }
|
||||
.ok { color:rgb(0,200,0); font-weight:bold}
|
||||
.failed { color:rgb(200,0,0); font-weight:bold}
|
||||
|
||||
span.box {
|
||||
border: black solid 1px;
|
||||
border-right:solid black 2px;
|
||||
border-bottom:solid black 2px;
|
||||
padding:0 0.5em 0 0.5em;
|
||||
margin-right:1em;
|
||||
}
|
||||
span.green { background:#60F060; padding:0 0.5em 0 0.5em}
|
||||
span.red { background:#D06030; padding:0 0.5em 0 0.5em }
|
||||
|
||||
div.authneeded {
|
||||
background:rgb(238,238,238);
|
||||
border:solid rgb(204,204,204) 1px;
|
||||
color:rgb(200,0,0);
|
||||
font-size:1.2em;
|
||||
font-weight:bold;
|
||||
padding:2em;
|
||||
text-align:center;
|
||||
}
|
||||
|
||||
input {
|
||||
background:rgb(153,153,204);
|
||||
border:solid rgb(102,102,153) 2px;
|
||||
color:white;
|
||||
font-weight:bold;
|
||||
margin-right:1em;
|
||||
padding:0.1em 0.5em 0.1em 0.5em;
|
||||
}
|
||||
//-->
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="head">
|
||||
<h1 class="memcache">
|
||||
<span class="logo"><a href="http://pecl.php.net/package/memcache">memcache</a></span>
|
||||
<span class="nameinfo">memcache.php by <a href="http://livebookmark.net">Harun Yayli</a></span>
|
||||
</h1>
|
||||
<hr class="memcache">
|
||||
</div>
|
||||
<div class=content>
|
||||
EOB;
|
||||
|
||||
return $header;
|
||||
}
|
||||
function getFooter(){
|
||||
global $VERSION;
|
||||
$footer = '</div><!-- Based on apc.php '.$VERSION.'--></body>
|
||||
</html>
|
||||
';
|
||||
|
||||
return $footer;
|
||||
|
||||
}
|
||||
function getMenu(){
|
||||
global $PHP_SELF;
|
||||
echo "<ol class=menu>";
|
||||
if ($_GET['op']!=4){
|
||||
echo <<<EOB
|
||||
<li><a href="$PHP_SELF&op={$_GET['op']}">Refresh Data</a></li>
|
||||
EOB;
|
||||
}
|
||||
else {
|
||||
echo <<<EOB
|
||||
<li><a href="$PHP_SELF&op=2}">Back</a></li>
|
||||
EOB;
|
||||
}
|
||||
echo
|
||||
menu_entry(1,'View Host Stats'),
|
||||
menu_entry(2,'Variables');
|
||||
|
||||
echo <<<EOB
|
||||
</ol>
|
||||
<br/>
|
||||
EOB;
|
||||
}
|
||||
|
||||
// TODO, AUTH
|
||||
|
||||
$_GET['op'] = !isset($_GET['op'])? '1':$_GET['op'];
|
||||
$PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],'')) : '';
|
||||
|
||||
$PHP_SELF=$PHP_SELF.'?';
|
||||
$time = time();
|
||||
// sanitize _GET
|
||||
|
||||
foreach($_GET as $key=>$g){
|
||||
$_GET[$key]=htmlentities($g);
|
||||
}
|
||||
|
||||
|
||||
// singleout
|
||||
// when singleout is set, it only gives details for that server.
|
||||
if (isset($_GET['singleout']) && $_GET['singleout']>=0 && $_GET['singleout'] <count($MEMCACHE_SERVERS)){
|
||||
$MEMCACHE_SERVERS = array($MEMCACHE_SERVERS[$_GET['singleout']]);
|
||||
}
|
||||
|
||||
// display images
|
||||
if (isset($_GET['IMG'])){
|
||||
$memcacheStats = getMemcacheStats();
|
||||
$memcacheStatsSingle = getMemcacheStats(false);
|
||||
|
||||
if (!graphics_avail()) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
function fill_box($im, $x, $y, $w, $h, $color1, $color2,$text='',$placeindex='') {
|
||||
global $col_black;
|
||||
$x1=$x+$w-1;
|
||||
$y1=$y+$h-1;
|
||||
|
||||
imagerectangle($im, $x, $y1, $x1+1, $y+1, $col_black);
|
||||
if($y1>$y) imagefilledrectangle($im, $x, $y, $x1, $y1, $color2);
|
||||
else imagefilledrectangle($im, $x, $y1, $x1, $y, $color2);
|
||||
imagerectangle($im, $x, $y1, $x1, $y, $color1);
|
||||
if ($text) {
|
||||
if ($placeindex>0) {
|
||||
|
||||
if ($placeindex<16)
|
||||
{
|
||||
$px=5;
|
||||
$py=$placeindex*12+6;
|
||||
imagefilledrectangle($im, $px+90, $py+3, $px+90-4, $py-3, $color2);
|
||||
imageline($im,$x,$y+$h/2,$px+90,$py,$color2);
|
||||
imagestring($im,2,$px,$py-6,$text,$color1);
|
||||
|
||||
} else {
|
||||
if ($placeindex<31) {
|
||||
$px=$x+40*2;
|
||||
$py=($placeindex-15)*12+6;
|
||||
} else {
|
||||
$px=$x+40*2+100*intval(($placeindex-15)/15);
|
||||
$py=($placeindex%15)*12+6;
|
||||
}
|
||||
imagefilledrectangle($im, $px, $py+3, $px-4, $py-3, $color2);
|
||||
imageline($im,$x+$w,$y+$h/2,$px,$py,$color2);
|
||||
imagestring($im,2,$px+2,$py-6,$text,$color1);
|
||||
}
|
||||
} else {
|
||||
imagestring($im,4,$x+5,$y1-16,$text,$color1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function fill_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$color2,$text='',$placeindex=0) {
|
||||
$r=$diameter/2;
|
||||
$w=deg2rad((360+$start+($end-$start)/2)%360);
|
||||
|
||||
|
||||
if (function_exists("imagefilledarc")) {
|
||||
// exists only if GD 2.0.1 is avaliable
|
||||
imagefilledarc($im, $centerX+1, $centerY+1, $diameter, $diameter, $start, $end, $color1, IMG_ARC_PIE);
|
||||
imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2, IMG_ARC_PIE);
|
||||
imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color1, IMG_ARC_NOFILL|IMG_ARC_EDGED);
|
||||
} else {
|
||||
imagearc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2);
|
||||
imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2);
|
||||
imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start+1)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2);
|
||||
imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end-1)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2);
|
||||
imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2);
|
||||
imagefill($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2, $color2);
|
||||
}
|
||||
if ($text) {
|
||||
if ($placeindex>0) {
|
||||
imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1);
|
||||
imagestring($im,4,$diameter, $placeindex*12,$text,$color1);
|
||||
|
||||
} else {
|
||||
imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1);
|
||||
}
|
||||
}
|
||||
}
|
||||
$size = GRAPH_SIZE; // image size
|
||||
$image = imagecreate($size+50, $size+10);
|
||||
|
||||
$col_white = imagecolorallocate($image, 0xFF, 0xFF, 0xFF);
|
||||
$col_red = imagecolorallocate($image, 0xD0, 0x60, 0x30);
|
||||
$col_green = imagecolorallocate($image, 0x60, 0xF0, 0x60);
|
||||
$col_black = imagecolorallocate($image, 0, 0, 0);
|
||||
|
||||
imagecolortransparent($image,$col_white);
|
||||
|
||||
switch ($_GET['IMG']){
|
||||
case 1: // pie chart
|
||||
$tsize=$memcacheStats['limit_maxbytes'];
|
||||
$avail=$tsize-$memcacheStats['bytes'];
|
||||
$x=$y=$size/2;
|
||||
$angle_from = 0;
|
||||
$fuzz = 0.000001;
|
||||
|
||||
foreach($memcacheStatsSingle as $serv=>$mcs) {
|
||||
$free = $mcs['STAT']['limit_maxbytes']-$mcs['STAT']['bytes'];
|
||||
$used = $mcs['STAT']['bytes'];
|
||||
|
||||
|
||||
if ($free>0){
|
||||
// draw free
|
||||
$angle_to = ($free*360)/$tsize;
|
||||
$perc =sprintf("%.2f%%", ($free *100) / $tsize) ;
|
||||
|
||||
fill_arc($image,$x,$y,$size,$angle_from,$angle_from + $angle_to ,$col_black,$col_green,$perc);
|
||||
$angle_from = $angle_from + $angle_to ;
|
||||
}
|
||||
if ($used>0){
|
||||
// draw used
|
||||
$angle_to = ($used*360)/$tsize;
|
||||
$perc =sprintf("%.2f%%", ($used *100) / $tsize) ;
|
||||
fill_arc($image,$x,$y,$size,$angle_from,$angle_from + $angle_to ,$col_black,$col_red, '('.$perc.')' );
|
||||
$angle_from = $angle_from+ $angle_to ;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 2: // hit miss
|
||||
|
||||
$hits = ($memcacheStats['get_hits']==0) ? 1:$memcacheStats['get_hits'];
|
||||
$misses = ($memcacheStats['get_misses']==0) ? 1:$memcacheStats['get_misses'];
|
||||
$total = $hits + $misses ;
|
||||
|
||||
fill_box($image, 30,$size,50,-$hits*($size-21)/$total,$col_black,$col_green,sprintf("%.1f%%",$hits*100/$total));
|
||||
fill_box($image,130,$size,50,-max(4,($total-$hits)*($size-21)/$total),$col_black,$col_red,sprintf("%.1f%%",$misses*100/$total));
|
||||
break;
|
||||
|
||||
}
|
||||
header("Content-type: image/png");
|
||||
imagepng($image);
|
||||
exit;
|
||||
}
|
||||
|
||||
echo getHeader();
|
||||
echo getMenu();
|
||||
|
||||
switch ($_GET['op']) {
|
||||
|
||||
case 1: // host stats
|
||||
$phpversion = phpversion();
|
||||
$memcacheStats = getMemcacheStats();
|
||||
$memcacheStatsSingle = getMemcacheStats(false);
|
||||
|
||||
$mem_size = $memcacheStats['limit_maxbytes'];
|
||||
$mem_used = $memcacheStats['bytes'];
|
||||
$mem_avail= $mem_size-$mem_used;
|
||||
$startTime = time()-array_sum($memcacheStats['uptime']);
|
||||
|
||||
$curr_items = $memcacheStats['curr_items'];
|
||||
$total_items = $memcacheStats['total_items'];
|
||||
$hits = ($memcacheStats['get_hits']==0) ? 1:$memcacheStats['get_hits'];
|
||||
$misses = ($memcacheStats['get_misses']==0) ? 1:$memcacheStats['get_misses'];
|
||||
$sets = $memcacheStats['cmd_set'];
|
||||
|
||||
$req_rate = sprintf("%.2f",($hits+$misses)/($time-$startTime));
|
||||
$hit_rate = sprintf("%.2f",($hits)/($time-$startTime));
|
||||
$miss_rate = sprintf("%.2f",($misses)/($time-$startTime));
|
||||
$set_rate = sprintf("%.2f",($sets)/($time-$startTime));
|
||||
|
||||
echo <<< EOB
|
||||
<div class="info div1"><h2>General Cache Information</h2>
|
||||
<table cellspacing=0><tbody>
|
||||
<tr class=tr-1><td class=td-0>PHP Version</td><td>$phpversion</td></tr>
|
||||
EOB;
|
||||
echo "<tr class=tr-0><td class=td-0>Memcached Host". ((count($MEMCACHE_SERVERS)>1) ? 's':'')."</td><td>";
|
||||
$i=0;
|
||||
if (!isset($_GET['singleout']) && count($MEMCACHE_SERVERS)>1){
|
||||
foreach($MEMCACHE_SERVERS as $server){
|
||||
echo ($i+1).'. <a href="'.$PHP_SELF.'&singleout='.$i++.'">'.$server.'</a><br/>';
|
||||
}
|
||||
}
|
||||
else{
|
||||
echo '1.'.$MEMCACHE_SERVERS[0];
|
||||
}
|
||||
if (isset($_GET['singleout'])){
|
||||
echo '<a href="'.$PHP_SELF.'">(all servers)</a><br/>';
|
||||
}
|
||||
echo "</td></tr>\n";
|
||||
echo "<tr class=tr-1><td class=td-0>Total Memcache Cache</td><td>".bsize($memcacheStats['limit_maxbytes'])."</td></tr>\n";
|
||||
|
||||
echo <<<EOB
|
||||
</tbody></table>
|
||||
</div>
|
||||
|
||||
<div class="info div1"><h2>Memcache Server Information</h2>
|
||||
EOB;
|
||||
foreach($MEMCACHE_SERVERS as $server){
|
||||
echo '<table cellspacing=0><tbody>';
|
||||
echo '<tr class=tr-1><td class=td-1>'.$server.'</td><td><a href="'.$PHP_SELF.'&server='.array_search($server,$MEMCACHE_SERVERS).'&op=6">[<b>Flush this server</b>]</a></td></tr>';
|
||||
echo '<tr class=tr-0><td class=td-0>Start Time</td><td>',date(DATE_FORMAT,$memcacheStatsSingle[$server]['STAT']['time']-$memcacheStatsSingle[$server]['STAT']['uptime']),'</td></tr>';
|
||||
echo '<tr class=tr-1><td class=td-0>Uptime</td><td>',duration($memcacheStatsSingle[$server]['STAT']['time']-$memcacheStatsSingle[$server]['STAT']['uptime']),'</td></tr>';
|
||||
echo '<tr class=tr-0><td class=td-0>Memcached Server Version</td><td>'.$memcacheStatsSingle[$server]['STAT']['version'].'</td></tr>';
|
||||
echo '<tr class=tr-1><td class=td-0>Used Cache Size</td><td>',bsize($memcacheStatsSingle[$server]['STAT']['bytes']),'</td></tr>';
|
||||
echo '<tr class=tr-0><td class=td-0>Total Cache Size</td><td>',bsize($memcacheStatsSingle[$server]['STAT']['limit_maxbytes']),'</td></tr>';
|
||||
echo '</tbody></table>';
|
||||
}
|
||||
echo <<<EOB
|
||||
|
||||
</div>
|
||||
<div class="graph div3"><h2>Host Status Diagrams</h2>
|
||||
<table cellspacing=0><tbody>
|
||||
EOB;
|
||||
|
||||
$size='width='.(GRAPH_SIZE+50).' height='.(GRAPH_SIZE+10);
|
||||
echo <<<EOB
|
||||
<tr>
|
||||
<td class=td-0>Cache Usage</td>
|
||||
<td class=td-1>Hits & Misses</td>
|
||||
</tr>
|
||||
EOB;
|
||||
|
||||
echo
|
||||
graphics_avail() ?
|
||||
'<tr>'.
|
||||
"<td class=td-0><img alt=\"\" $size src=\"$PHP_SELF&IMG=1&".(isset($_GET['singleout'])? 'singleout='.$_GET['singleout'].'&':'')."$time\"></td>".
|
||||
"<td class=td-1><img alt=\"\" $size src=\"$PHP_SELF&IMG=2&".(isset($_GET['singleout'])? 'singleout='.$_GET['singleout'].'&':'')."$time\"></td></tr>\n"
|
||||
: "",
|
||||
'<tr>',
|
||||
'<td class=td-0><span class="green box"> </span>Free: ',bsize($mem_avail).sprintf(" (%.1f%%)",$mem_avail*100/$mem_size),"</td>\n",
|
||||
'<td class=td-1><span class="green box"> </span>Hits: ',$hits.sprintf(" (%.1f%%)",$hits*100/($hits+$misses)),"</td>\n",
|
||||
'</tr>',
|
||||
'<tr>',
|
||||
'<td class=td-0><span class="red box"> </span>Used: ',bsize($mem_used ).sprintf(" (%.1f%%)",$mem_used *100/$mem_size),"</td>\n",
|
||||
'<td class=td-1><span class="red box"> </span>Misses: ',$misses.sprintf(" (%.1f%%)",$misses*100/($hits+$misses)),"</td>\n";
|
||||
echo <<< EOB
|
||||
</tr>
|
||||
</tbody></table>
|
||||
<br/>
|
||||
<div class="info"><h2>Cache Information</h2>
|
||||
<table cellspacing=0><tbody>
|
||||
<tr class=tr-0><td class=td-0>Current Items(total)</td><td>$curr_items ($total_items)</td></tr>
|
||||
<tr class=tr-1><td class=td-0>Hits</td><td>{$hits}</td></tr>
|
||||
<tr class=tr-0><td class=td-0>Misses</td><td>{$misses}</td></tr>
|
||||
<tr class=tr-1><td class=td-0>Request Rate (hits, misses)</td><td>$req_rate cache requests/second</td></tr>
|
||||
<tr class=tr-0><td class=td-0>Hit Rate</td><td>$hit_rate cache requests/second</td></tr>
|
||||
<tr class=tr-1><td class=td-0>Miss Rate</td><td>$miss_rate cache requests/second</td></tr>
|
||||
<tr class=tr-0><td class=td-0>Set Rate</td><td>$set_rate cache requests/second</td></tr>
|
||||
</tbody></table>
|
||||
</div>
|
||||
|
||||
EOB;
|
||||
|
||||
break;
|
||||
|
||||
case 2: // variables
|
||||
|
||||
$m=0;
|
||||
$cacheItems= getCacheItems();
|
||||
$items = $cacheItems['items'];
|
||||
$totals = $cacheItems['counts'];
|
||||
$maxDump = MAX_ITEM_DUMP;
|
||||
foreach($items as $server => $entries) {
|
||||
|
||||
echo <<< EOB
|
||||
|
||||
<div class="info"><table cellspacing=0><tbody>
|
||||
<tr><th colspan="2">$server</th></tr>
|
||||
<tr><th>Slab Id</th><th>Info</th></tr>
|
||||
EOB;
|
||||
|
||||
foreach($entries as $slabId => $slab) {
|
||||
$dumpUrl = $PHP_SELF.'&op=2&server='.(array_search($server,$MEMCACHE_SERVERS)).'&dumpslab='.$slabId;
|
||||
echo
|
||||
"<tr class=tr-$m>",
|
||||
"<td class=td-0><center>",'<a href="',$dumpUrl,'">',$slabId,'</a>',"</center></td>",
|
||||
"<td class=td-last><b>Item count:</b> ",$slab['number'],'<br/><b>Age:</b>',duration($time-$slab['age']),'<br/> <b>Evicted:</b>',((isset($slab['evicted']) && $slab['evicted']==1)? 'Yes':'No');
|
||||
if ((isset($_GET['dumpslab']) && $_GET['dumpslab']==$slabId) && (isset($_GET['server']) && $_GET['server']==array_search($server,$MEMCACHE_SERVERS))){
|
||||
echo "<br/><b>Items: item</b><br/>";
|
||||
$items = dumpCacheSlab($server,$slabId,$slab['number']);
|
||||
// maybe someone likes to do a pagination here :)
|
||||
$i=1;
|
||||
foreach($items['ITEM'] as $itemKey=>$itemInfo){
|
||||
$itemInfo = trim($itemInfo,'[ ]');
|
||||
|
||||
|
||||
echo '<a href="',$PHP_SELF,'&op=4&server=',(array_search($server,$MEMCACHE_SERVERS)),'&key=',base64_encode($itemKey).'">',$itemKey,'</a>';
|
||||
if ($i++ % 10 == 0) {
|
||||
echo '<br/>';
|
||||
}
|
||||
elseif ($i!=$slab['number']+1){
|
||||
echo ',';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo "</td></tr>";
|
||||
$m=1-$m;
|
||||
}
|
||||
echo <<<EOB
|
||||
</tbody></table>
|
||||
</div><hr/>
|
||||
EOB;
|
||||
}
|
||||
break;
|
||||
|
||||
break;
|
||||
|
||||
case 4: //item dump
|
||||
if (!isset($_GET['key']) || !isset($_GET['server'])){
|
||||
echo "No key set!";
|
||||
break;
|
||||
}
|
||||
// I'm not doing anything to check the validity of the key string.
|
||||
// probably an exploit can be written to delete all the files in key=base64_encode("\n\r delete all").
|
||||
// somebody has to do a fix to this.
|
||||
$theKey = htmlentities(base64_decode($_GET['key']));
|
||||
|
||||
$theserver = $MEMCACHE_SERVERS[(int)$_GET['server']];
|
||||
list($h,$p) = get_host_port_from_server($theserver);
|
||||
$r = sendMemcacheCommand($h,$p,'get '.$theKey);
|
||||
echo <<<EOB
|
||||
<div class="info"><table cellspacing=0><tbody>
|
||||
<tr><th>Server<th>Key</th><th>Value</th><th>Delete</th></tr>
|
||||
EOB;
|
||||
if (!isset($r['VALUE'])) {
|
||||
echo "<tr><td class=td-0>",$theserver,"</td><td class=td-0>",$theKey,
|
||||
"</td><td>[The requested item was not found or has expired]</td>",
|
||||
"<td></td>","</tr>";
|
||||
}
|
||||
else {
|
||||
|
||||
echo "<tr><td class=td-0>",$theserver,"</td><td class=td-0>",$theKey,
|
||||
" <br/>flag:",$r['VALUE'][$theKey]['stat']['flag'],
|
||||
" <br/>Size:",bsize($r['VALUE'][$theKey]['stat']['size']),
|
||||
"</td><td>",chunk_split($r['VALUE'][$theKey]['value'],40),"</td>",
|
||||
'<td><a href="',$PHP_SELF,'&op=5&server=',(int)$_GET['server'],'&key=',base64_encode($theKey),"\">Delete</a></td>","</tr>";
|
||||
}
|
||||
echo <<<EOB
|
||||
</tbody></table>
|
||||
</div><hr/>
|
||||
EOB;
|
||||
break;
|
||||
case 5: // item delete
|
||||
if (!isset($_GET['key']) || !isset($_GET['server'])){
|
||||
echo "No key set!";
|
||||
break;
|
||||
}
|
||||
$theKey = htmlentities(base64_decode($_GET['key']));
|
||||
$theserver = $MEMCACHE_SERVERS[(int)$_GET['server']];
|
||||
list($h,$p) = get_host_port_from_server($theserver);
|
||||
$r = sendMemcacheCommand($h,$p,'delete '.$theKey);
|
||||
echo 'Deleting '.$theKey.':'.$r;
|
||||
break;
|
||||
|
||||
case 6: // flush server
|
||||
$_GET['server'] = empty($_GET['server']) ? 0 : $_GET['server'];
|
||||
$theserver = $MEMCACHE_SERVERS[(int)$_GET['server']];
|
||||
$r = flushServer($theserver);
|
||||
echo 'Flush '.$theserver.":".$r;
|
||||
break;
|
||||
}
|
||||
echo getFooter();
|
||||
|
||||
?>
|
||||
Binary file not shown.
BIN
laragon.exe
BIN
laragon.exe
Binary file not shown.
@@ -1,10 +1,10 @@
|
||||
# PHP
|
||||
# https://windows.php.net/download/
|
||||
# NTS = Non Thread Safe
|
||||
*PHP-8.4=https://windows.php.net/downloads/releases/php-8.4.2-nts-Win32-vs17-x64.zip
|
||||
*PHP-8.3=https://windows.php.net/downloads/releases/php-8.3.15-nts-Win32-vs16-x64.zip
|
||||
*PHP-8.2=https://windows.php.net/downloads/releases/php-8.2.27-nts-Win32-vs16-x64.zip
|
||||
*PHP-8.1=https://windows.php.net/downloads/releases/php-8.1.31-nts-Win32-vs16-x64.zip
|
||||
*PHP-8.4=https://windows.php.net/downloads/releases/archives/php-8.4.2-nts-Win32-vs17-x64.zip
|
||||
*PHP-8.3=https://windows.php.net/downloads/releases/archives/php-8.3.15-nts-Win32-vs16-x64.zip
|
||||
*PHP-8.2=https://windows.php.net/downloads/releases/archives/php-8.2.27-nts-Win32-vs16-x64.zip
|
||||
*PHP-8.1=https://windows.php.net/downloads/releases/archives/php-8.1.31-nts-Win32-vs16-x64.zip
|
||||
|
||||
|
||||
---
|
||||
|
||||
231
www/index.php
231
www/index.php
@@ -1,167 +1,106 @@
|
||||
<?php
|
||||
if (!empty($_GET['q'])) {
|
||||
switch ($_GET['q']) {
|
||||
case 'info':
|
||||
phpinfo();
|
||||
exit;
|
||||
break;
|
||||
}
|
||||
$query = htmlspecialchars($_GET['q'], ENT_QUOTES, 'UTF-8');
|
||||
|
||||
switch ($query) {
|
||||
case 'info':
|
||||
phpinfo();
|
||||
exit;
|
||||
default:
|
||||
header("HTTP/1.0 404 Not Found");
|
||||
echo "Invalid query parameter.";
|
||||
exit;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Laragon</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Karla:400" rel="stylesheet" type="text/css">
|
||||
<link rel="shortcut icon" href="https://i.imgur.com/ky9oqct.png" type="image/png">
|
||||
<style>
|
||||
*,
|
||||
:before *,
|
||||
:after * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Laragon</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Karla:400" rel="stylesheet" type="text/css">
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Karla', sans-serif;
|
||||
font-weight: 100;
|
||||
background-color: #f9f9f9;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
min-height: 100vh;
|
||||
font-weight: 100;
|
||||
font-family: 'Karla', sans-serif;
|
||||
font-size: 18px;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
header,
|
||||
main,
|
||||
nav,
|
||||
aside {
|
||||
padding: 1rem;
|
||||
margin: auto;
|
||||
max-width: 1200px;
|
||||
text-align: center;
|
||||
}
|
||||
.content {
|
||||
max-width: 800px;
|
||||
padding: 100px;
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
header {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
.title {
|
||||
font-size: 60px;
|
||||
margin: 0;
|
||||
|
||||
.header__item {
|
||||
margin: 0;
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.header--logo {
|
||||
height: 8rem;
|
||||
}
|
||||
.info {
|
||||
margin-top: 20px;
|
||||
font-size: 18px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 5rem;
|
||||
}
|
||||
.info a {
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
main {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
.info a:hover {
|
||||
color: #0056b3;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
nav {
|
||||
width: 100%;
|
||||
}
|
||||
.opt {
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: auto;
|
||||
}
|
||||
.opt a {
|
||||
font-size: 18px;
|
||||
color: #007bff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #37ADFF;
|
||||
font-weight: 900;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: red;
|
||||
font-weight: 900;
|
||||
transition: 300ms;
|
||||
}
|
||||
|
||||
main a {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
nav a {
|
||||
display: block;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
nav a:after {
|
||||
content: '→';
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
|
||||
.alert {
|
||||
color: red;
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
@media (min-width: 650px) {
|
||||
h1 {
|
||||
font-size: 10rem;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
.opt a:hover {
|
||||
color: #0056b3;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<img class="header__item header--logo" src="https://i.imgur.com/ky9oqct.png" alt="Offline">
|
||||
<h1 class="header__item header--title" title="Laragon">Laragon</h1>
|
||||
</header>
|
||||
<main>
|
||||
<p>
|
||||
<?php print($_SERVER['SERVER_SOFTWARE']); ?>
|
||||
</p>
|
||||
<p>
|
||||
PHP version: <?php print PHP_VERSION; ?> <span><a title="phpinfo()" href="/?q=info">info</a></span>
|
||||
</p>
|
||||
<p>
|
||||
Document Root: <?php print($_SERVER['DOCUMENT_ROOT']); ?>
|
||||
</p>
|
||||
<p>
|
||||
<a title="Getting Started" href="https://laragon.org/docs">Getting Started</a>
|
||||
</p>
|
||||
</main>
|
||||
<?php
|
||||
$dirList = glob('*', GLOB_ONLYDIR);
|
||||
if (!empty($dirList)) :
|
||||
?>
|
||||
<nav>
|
||||
<ul>
|
||||
<?php
|
||||
foreach ($dirList as $key => $value) :
|
||||
$link = 'https://' . $value . '.test';
|
||||
?>
|
||||
<a href="<?php echo $link; ?>" target="_blank"><?php echo $link; ?></a>
|
||||
<?php
|
||||
endforeach;
|
||||
?>
|
||||
</ul>
|
||||
</nav>
|
||||
<?php
|
||||
else :
|
||||
?>
|
||||
<aside>
|
||||
<p class="alert">There are no directories, create your first project now</p>
|
||||
<div>
|
||||
<img src="https://i.imgur.com/3Sgu8XI.png" alt="Offline">
|
||||
</div>
|
||||
</aside>
|
||||
<?php
|
||||
endif;
|
||||
?>
|
||||
<div class="container">
|
||||
<div class="content">
|
||||
<h1 class="title" title="Laragon">Laragon</h1>
|
||||
<div class="info">
|
||||
<p><?php echo htmlspecialchars($_SERVER['SERVER_SOFTWARE'], ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
<p>PHP version: <?php echo htmlspecialchars(phpversion(), ENT_QUOTES, 'UTF-8'); ?>
|
||||
<a title="phpinfo()" href="/?q=info">info</a>
|
||||
</p>
|
||||
<p>Document Root: <?php echo htmlspecialchars($_SERVER['DOCUMENT_ROOT'], ENT_QUOTES, 'UTF-8'); ?></p>
|
||||
</div>
|
||||
<div class="opt">
|
||||
<p><a title="Getting Started" href="https://laragon.org/docs">Getting Started</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user