36 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
b0885989e4 Update version information to clarify auto-update system and current software versions
Co-authored-by: alxndr-w <3855487+alxndr-w@users.noreply.github.com>
2025-09-05 07:38:06 +00:00
Alexander Walther
00d8a84e16 Update .github/copilot-instructions.md
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-09-05 09:33:15 +02:00
copilot-swe-agent[bot]
fee18b42db Add comprehensive GitHub Copilot instructions for Laragon repository
Co-authored-by: alxndr-w <3855487+alxndr-w@users.noreply.github.com>
2025-09-05 07:11:59 +00:00
copilot-swe-agent[bot]
11e3ffc1d2 Initial plan 2025-09-05 07:04:30 +00:00
Leo Khoa
cf4bcd6d9f Merge pull request #1258 from jaideejung007/master
Add Thai Translation
2025-07-26 10:49:20 +07:00
jaideejung007
df3d72b936 Add Thai Translation 2025-07-24 09:55:06 +07:00
Leo Khoa
5d48b71858 Improve verifying license process 2025-07-17 18:19:08 +02:00
Leo Khoa
75a4430457 Allow root login without a password #1240 2025-07-16 03:24:45 +02:00
Leo Khoa
705c0da87b Fix close to system tray issue #1219 2025-06-29 13:29:31 +02:00
Leo Khoa
6a9a83fb47 Improve AutoSSL 2025-05-25 18:43:37 +02:00
Leo Khoa
593338f8f8 Update the laragon core 2025-05-01 11:20:45 +02:00
Leo Khoa
f403e94463 Merge pull request #1147 from AhmedAlaa4611/master
Remove trailing whitespace
2025-05-01 11:18:15 +02:00
Ahmed Alaa
ec467a6f33 Remove trailing whitespace 2025-05-01 11:34:28 +03:00
Leo Khoa
4b7289618f Update resources info to match with the latest version 2025-04-23 17:57:22 +02:00
Leo Khoa
b716689318 Fixed license issue on old server
Crash when inserting license key in Laragon 8 on Windows Server 2012 R2
https://github.com/leokhoa/laragon/discussions/1106
2025-04-03 11:02:25 +02:00
Leo Khoa
b99af56576 Update Laragon 2025-04-03 10:48:48 +02:00
Leo Khoa
45219c7b39 Add files via upload 2025-03-24 10:02:51 +01:00
Leo Khoa
98a6ced6b0 Update CHANGELOG.md 2025-03-18 21:40:52 +01:00
Leo Khoa
620dc8bc72 Merge pull request #1077 from leokhoa/alxndr-w-patch-1
Update README.md with license information
2025-03-18 21:39:46 +01:00
Alexander Walther
3ad0d09569 Update README.md with license information 2025-03-18 13:21:43 +01:00
Leo Khoa
9fdd698e09 Fixed minor issues 2025-03-14 18:13:00 +01:00
Leo Khoa
ea6254fc80 Laragon 8.0.0 2025-03-13 21:25:13 +01:00
Leo Khoa
566be5ce9f Update sites.conf 2025-03-13 21:24:27 +01:00
Leo Khoa
959aab1bc7 Merge pull request #1057 from leokhoa/leokhoa-patch-3
Update packages.conf
2025-03-13 21:22:50 +01:00
Leo Khoa
3f0534e0e1 Update packages.conf 2025-03-13 21:22:11 +01:00
Leo Khoa
6d0ca768f9 Update packages.conf
Fix broken PHP links
2025-02-27 08:18:10 +01:00
Leo Khoa
1bf6169ffc Track changes from version 7.0.0 2025-02-06 11:04:39 +01:00
Leo Khoa
6959b13189 Fix css issue
https://github.com/leokhoa/laragon/issues/339
2025-02-03 22:33:56 +01:00
Leo Khoa
2631fda37b Fix bug #689
https://github.com/leokhoa/laragon/issues/689
2025-02-03 22:32:38 +01:00
Leo Khoa
3fcd32d767 Merge pull request #1007 from leokhoa/leokhoa-patch-2
Update SECURITY.md
2025-02-02 13:01:08 +01:00
Leo Khoa
b371252f27 Update SECURITY.md 2025-02-02 13:00:25 +01:00
Leo Khoa
18992b2d5c Improve Laragon to work with virtual machine 2025-01-28 20:09:08 +01:00
Leo Khoa
5cf5f6b2ae Add more logs 2025-01-28 18:38:13 +01:00
Leo Khoa
45d2c3f117 Delete etc/apps directory as it is obsolete 2025-01-27 19:57:51 +01:00
Leo Khoa
f58e47d630 Merge pull request #988 from leokhoa/security_md
Create SECURITY.md
2025-01-26 22:22:57 +01:00
Alexander Walther
b23f970bea Create SECURITY.md 2025-01-26 22:10:16 +01:00
45 changed files with 747 additions and 6909 deletions

223
.github/copilot-instructions.md vendored Normal file
View File

@@ -0,0 +1,223 @@
# Laragon - Windows Development Environment
Laragon is a portable, isolated Windows development environment for PHP, Node.js, and Python. This repository contains the distribution files and configuration templates for Laragon.
Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.
## Critical Limitations
**WINDOWS-ONLY ENVIRONMENT**: Laragon is exclusively a Windows GUI application. The main executable (laragon.exe) is a Windows PE32+ binary that cannot run on Linux or macOS. Development and testing of the actual Laragon environment requires Windows.
**NO BUILD PROCESS**: This repository contains pre-built binaries and configuration files. There is no source code compilation, build system, or CI/CD pipeline.
**NO AUTOMATED TESTS**: This is a packaged application distribution, not a development project with test suites.
## Working Effectively on Linux/macOS
While you cannot run Laragon itself, you can:
### Repository Structure Exploration
- View and understand the file structure: `ls -la /path/to/laragon`
- Examine configuration files: `find . -name "*.ini" -o -name "*.conf"`
- Check included software versions: `grep -r "Version=" usr/laragon.ini`
- List bundled tools: `ls -la bin/`
### Configuration Management
- View main configuration: `cat usr/laragon.ini`
- Check site templates: `cat usr/sites.conf`
- Examine Procfile format: `cat usr/Procfile`
- Review user customization: `cat usr/user.cmd`
### Documentation Tasks
- Edit README.md and documentation files
- Update configuration templates
- Modify default project templates in www/
- Update site configuration examples
## Laragon Architecture
### Core Components
- **laragon.exe**: Main Windows GUI application (5.3MB PE32+ executable)
- **bin/**: Bundled software packages
- PHP (current versions with auto-update support)
- MySQL (current versions with auto-update support)
- Nginx (current versions)
- Apache (configurable)
- Composer (PHP dependency manager)
- HeidiSQL (database management GUI)
- Cmder (terminal emulator)
- Notepad++ (text editor)
- Sendmail (mail handling)
**Note**: This repository contains historical/example versions (PHP 5.4.9, MySQL 5.1.72, Nginx 1.14.0) but actual Laragon releases bundle current software versions with an integrated auto-update system for minor version updates.
### Configuration Files
- **usr/laragon.ini**: Main configuration (service versions, preferences)
- **usr/sites.conf**: Project template definitions
- **usr/Procfile**: Custom service definitions
- **usr/user.cmd**: User startup customizations
- **etc/**: Service-specific configurations (Apache, Nginx, PHP)
### Directory Structure
```
laragon/
├── laragon.exe # Main Windows GUI application
├── bin/ # Bundled software (PHP, MySQL, Nginx, etc.)
├── etc/ # Configuration files for services
├── usr/ # User configurations and templates
├── www/ # Default web root directory
├── README.md # Project documentation
├── CHANGELOG.md # Version history
└── SECURITY.md # Security policy
```
## Key Features
- **Portable**: Entire environment can be moved between Windows machines
- **Auto-configuration**: Services are automatically configured when started
- **Auto-update system**: Integrated minor version updates for bundled software
- **Current software versions**: Ships with up-to-date PHP, MySQL, Apache, and other tools
- **Pretty URLs**: Uses `.test` domains instead of localhost
- **Multi-version support**: Can switch between different PHP/MySQL versions
- **Project templates**: Built-in templates for WordPress, Laravel, Symfony
## Common Tasks
### Examining Service Versions
```bash
# Check configured versions (note: repository contains historical versions)
grep "Version=" usr/laragon.ini
# List available software in bin directory (historical snapshot)
ls bin/
```
**Important**: The versions shown in this repository (PHP 5.4.9, MySQL 5.1.72, etc.) are historical examples. Actual Laragon installations include current software versions with automatic update capabilities.
### Configuration File Management
```bash
# View main configuration
cat usr/laragon.ini
# Check site template definitions
cat usr/sites.conf
# Examine user customization file
cat usr/user.cmd
```
### Project Template Analysis
```bash
# Check available project types
grep "^[A-Za-z]" usr/sites.conf | grep "="
# View default web page
cat www/index.php
```
### Structure Exploration
```bash
# Repository root contents
ls -la
# Find all configuration files
find . -name "*.ini" -o -name "*.conf" | head -10
# Check documentation files
find . -name "*.md"
```
## Validation on Windows
**Note**: These steps can only be performed on a Windows machine with Laragon installed:
### Basic Functionality Testing
1. Start Laragon GUI application
2. Verify all services start (Apache/Nginx, MySQL, PHP)
3. Access http://localhost to see default page
4. Create a test project using quick app creation
5. Verify pretty URLs work (e.g., http://testapp.test)
### Configuration Validation
1. Modify usr/laragon.ini settings
2. Restart Laragon to apply changes
3. Verify service versions match configuration
4. Test custom Procfile entries
5. Validate user.cmd customizations
## File Editing Guidelines
### Safe to Edit
- **Documentation**: README.md, CHANGELOG.md, SECURITY.md
- **Configuration templates**: usr/laragon.ini, usr/sites.conf
- **Default web content**: www/index.php
- **User scripts**: usr/user.cmd, usr/Procfile
### Do Not Modify
- **Binary files**: laragon.exe, all files in bin/
- **Service configurations**: etc/ files (unless creating templates)
- **Git ignored items**: See .gitignore for excluded files
## Development Workflow
### For Configuration Changes
1. Edit configuration files using text editors
2. Validate syntax if applicable (e.g., INI format for laragon.ini)
3. Test changes on Windows Laragon installation
4. Document changes in comments or README
### For Documentation Updates
1. Edit Markdown files directly
2. Ensure proper formatting and links
3. Validate Markdown syntax
4. No special testing required
## Repository Maintenance
### Adding New Project Templates
1. Edit usr/sites.conf
2. Follow existing format: `ProjectName=installation_command`
3. Test template on Windows Laragon installation
4. Document new template in README if needed
### Configuration Updates
1. Modify relevant .ini or .conf files
2. Ensure Windows compatibility
3. Test with actual Laragon installation
4. Update documentation if behavior changes
## Common File Locations
### Frequently Referenced Files
```bash
# Main configuration
usr/laragon.ini
# Project templates
usr/sites.conf
# Default web page
www/index.php
# User customization
usr/user.cmd
# Main documentation
README.md
```
### Configuration Paths
```bash
# Apache configuration
etc/apache2/
# Nginx configuration
etc/nginx/
# PHP configuration
etc/php/
# SSL certificates
etc/ssl/
```
This repository serves as the distribution package for Laragon. All development and testing of the actual development environment functionality must be done on Windows machines with Laragon installed.

1
CHANGELOG.md Normal file
View File

@@ -0,0 +1 @@
https://github.com/leokhoa/laragon/releases

View File

@@ -6,18 +6,20 @@ Laragon is a portable, isolated, fast & powerful universal development environme
Laragon is great for building and managing modern web applications. It is focused on performance - designed around stability, simplicity, flexibility and freedom.
Laragon is very lightweight and will stay as lean as possible. The core binary itself is less than 2MB and uses less than 4MB RAM when running.
Laragon is very lightweight and will stay as lean as possible. The core binary itself is less than 6MB and uses around 4MB - 10MB RAM when running.
Laragon doesn't use Windows services. It has its own `service orchestration` which manages services asynchronously and non-blocking so you'll find things run fast & smoothly with Laragon.
Enjoy!
> Starting with Laragon 7.x, a license is required to use Laragon. For more details, visit <https://laragon.lemonsqueezy.com/>.
## Features
- **Pretty URLs**
Use `app.test` instead of `localhost/app`.
- **Portable**
You can move Laragon folder around (to another disks, to another laptops, sync to Cloud,...) without any worries.
You can move Laragon folder around (to another disks, to another laptops, sync to Cloud,...) without any worries.
- **Isolated**
Laragon has an isolated environment with your OS - it will keep your system clean.
- **Easy Operation**
@@ -26,7 +28,7 @@ Enjoy!
Laragon comes with a modern architecture which is suitable to build modern web apps. You can work with both Apache & Nginx as they are fully-managed.
Also, Laragon makes things a lot easier:
- Wanna have a Wordpress CMS? Just 1 click.
- Wanna show your local project to customers? Just 1 click.
- Wanna show your local project to customers? Just 1 click.
- Wanna enable/disable a PHP extension? Just 1 click.
@@ -37,7 +39,7 @@ Enjoy!
## How fast?
Laragon starts instantly. You can set Laragon autorun when Windows starts. When running, Laragon uses just a little amount of your RAM.
Here is the GUI of Laragon:
![0_1513173700919_01-dashboard.png](https://i.imgur.com/0py3k1X.png)
![0_1513173700919_01-dashboard.png](https://i.imgur.com/0py3k1X.png)
## How easy?
- Laragon is very easy to install & upgrade. Just download the latest version and click `Next, Next, Next...`

13
SECURITY.md Normal file
View 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.

321
bin/laragon/lang/Thai.txt Normal file
View File

@@ -0,0 +1,321 @@
--------------------------------------------------------
version: 8.0.0
author: jaideejung007
date: 20250724
--------------------------------------------------------
# Main Interface
100 = เริ่มทั้งหมด
101 = เว็บ
102 = ฐานข้อมูล
103 = Terminal
104 = Root
105 = หยุด
106 = กำลังหยุด...
107 = รีโหลด
108 = เริ่ม
109 = เวอร์ชัน
110 = เปิดใช้งาน
111 = หยุดทั้งหมด
112 = ปิด
113 = ย่อ
114 = ขยาย
115 = ใช่
116 = ไม่
117 = ยกเลิก
118 = ตกลง
119 = เปิด
120 = ปิด
121 = เมนู
122 = หากคุณมีคำถาม โปรดติดต่อ
# Menu
199 = www
200 = เครื่องมือ
201 = Path
202 = ถ่ายโอนไฟล์
203 = สร้างโปรเจกต์
204 = สลับโปรเจกต์
205 = สร้างฐานข้อมูล
206 = เปลี่ยนรหัสผ่าน root
207 = Mail Catcher
208 = ดูอีเมลล่าสุด
209 = เปิดโฟลเดอร์อีเมล
210 = คัดลอก sendmail_path
211 = การกำหนดค่า
212 = ตัวส่งอีเมล
213 = ส่วนขยาย
214 = ผู้ดูแลเว็บ
215 = ล็อกอิน
216 = การตั้งค่า
217 = ออก
218 = ชื่อโปรเจกต์
# Preferences
300 = ทั่วไป
301 = เซอร์วิส && พอร์ต
310 = รัน Laragon เมื่อ Windows เริ่มทำงาน
311 = รัน Laragon อัตโนมัติเมื่อ Windows เริ่มทำงาน
312 = รันแบบย่อหน้าต่าง
# \n for a new line
313 = ย่อ Laragon ไปที่ System Tray\nคลิกซ้ายที่ไอคอนของ Laragon ใน System Tray เพื่อแสดง Laragon
314 = เริ่มทั้งหมดอัตโนมัติ
315 = เริ่มเซอร์วิสที่เลือกทั้งหมดโดยอัตโนมัติเมื่อ Laragon รัน
316 = ภาษา
317 = Document Root
318 = คลิกเพื่อเปลี่ยน Document Root
319 = ไดเรกทอรีข้อมูล
320 = คลิกเพื่อเปลี่ยน DataDir ของ MySQL
322 = สร้าง Virtual Hosts อัตโนมัติ
323 = เพียงวางโฟลเดอร์ใน Document Root และรีโหลด Apache Laragon จะสร้างชื่อโฮสต์ที่สอดคล้องกันในไฟล์ hosts และ Virtual Hosts ของ Apache ให้โดยอัตโนมัติ
# %s for a string placeholder
324 = ชื่อโฮสต์
325 = รูปแบบชื่อโฮสต์\nตัวอย่าง: ถ้าชื่อโปรเจกต์ของคุณคือ %s
328 = ขั้นสูง
329 = เมื่อฟังก์ชัน mail() ถูกเรียก Laragon จะแสดงข้อมูลอีเมล\nในหน้าต่างเล็กๆ ที่มุมขวาล่างของหน้าจอ
330 = หน้าต่างจะแสดงเป็นเวลา
331 = ฟีเจอร์นี้ช่วยให้คุณตรวจสอบเนื้อหาอีเมลได้อย่างรวดเร็ว\nคุณยังสามารถดูเนื้อหาของอีเมลล่าสุดได้ทาง:\nเมนู > PHP > MailCatcher
340 = ชื่อบัญชี Gmail
341 = รหัสผ่านบัญชี Gmail
342 = ทดสอบการส่งอีเมล
343 = คุณอาจต้องอนุญาต "การเข้าถึงของแอปที่มีความปลอดภัยน้อย" ในบัญชี Google ของคุณ\nรหัสผ่าน Gmail ของคุณจะถูกเข้ารหัส\nเมื่อเปิดใช้งาน คุณสามารถส่งอีเมลได้อย่างง่ายดายด้วยโค้ดเพียงบรรทัดเดียว:
# Mail Analyzer
350 = ตัววิเคราะห์อีเมล
351 = ส่งอีเมลทดสอบไปที่
352 = ทดสอบอีกครั้ง
353 = ทดสอบการส่งอีเมลอีกครั้ง คุณสามารถป้อนที่อยู่อีเมลอื่นเพื่อทดสอบได้
354 = ปิด
# System Tray
400 = Laragon ถูกย่อไว้ที่นี่
401 = สลับไปยังโปรเจกต์:
402 = สร้างฐานข้อมูลแล้ว
403 = เปลี่ยนรหัสผ่าน root ของ MySQL สำเร็จแล้ว
404 = รีโหลด Apache แล้ว
405 = Path ไม่ถูกต้อง
406 = ตรวจพบโปรเจกต์ใหม่\nLaragon จะเรียก nodejs เพื่อสร้าง Virtual Hosts ให้คุณ
# Hint
500 = ช่วยเหลือออนไลน์
501 = คลิกซ้าย: เปิด Laragon - คลิกขวา: เมนู
502 = หน้าเริ่มต้น
503 = การจัดการฐานข้อมูล
504 = เปิด Terminal (Cmder)
505 = Laragon จะเรียก nodejs เพื่อสร้าง Virtual Hosts ให้คุณ\nหากคุณต้องการฟีเจอร์นี้โดยไม่ต้องเรียก nodejs:\nรัน Laragon ในฐานะ Administrator
506 = Document Root
# Quick create website/project
600 = กำลังสร้าง
601 = สร้างแล้ว
602 = กำลังดาวน์โหลด
603 = ดาวน์โหลดแล้ว
604 = กำลังแตกไฟล์
605 = แตกไฟล์แล้ว
606 = สร้าง URL แบบอ่านง่ายแล้ว
607 = แอปด่วน
608 = ชื่อเว็บไซต์
609 = กรุณาระบุชื่อโปรเจกต์
610 = สร้าง %s สำเร็จแล้ว
611 = ไม่สามารถสร้าง %s ได้ เหตุผล: %s
612 = สำรวจ
613 = คลิกเพื่อไปยังโฟลเดอร์ของโปรเจกต์
614 = คลิกเพื่อเยี่ยมชมเว็บไซต์
# Messages
700 = sendmail_path ถูกคัดลอกไปยังคลิปบอร์ดแล้ว
701 = ฟีเจอร์นี้ไม่พร้อมใช้งานบนคอมพิวเตอร์ของคุณ
702 = กรุณาเริ่ม %s ก่อน
703 = ชื่อไม่ถูกต้อง
704 = ไดเรกทอรีนี้ไม่มีโปรเจกต์ Laravel ที่ถูกต้อง
705 = กรุณาเริ่ม PHP Server
706 = ไปที่ เมนู > การตั้งค่า > เซอร์วิส & พอร์ต และเปิดใช้งาน PHP Server
707 = มีโปรเจกต์นี้อยู่แล้ว
708 = หากคุณต้องการสร้างโปรเจกต์จริงๆ ให้ลบโฟลเดอร์ของโปรเจกต์แล้วลองอีกครั้ง
709 = ไม่มีโฟลเดอร์
710 = ไม่มีไฟล์
711 = %s ไม่ได้ทำงานอยู่ กรุณาเริ่ม Redis Server ก่อน
712 = Path ที่ติดตั้ง Laragon ไม่ควรมีช่องว่าง (เพื่อหลีกเลี่ยงปัญหาที่อาจเกิดขึ้น)
713 = เซอร์วิส %s กำลังทำงานอยู่ แต่ภายใต้โปรเซสอื่น
714 = กรุณาหยุด WAMP stack ปัจจุบันของคุณ มิฉะนั้นการทำงานของ Laragon อาจไม่สามารถคาดเดาได้
715 = Path ของโปรเซส:
# Hope you never see these :)
716 = อุ๊ปส์! เกิดข้อผิดพลาดบางอย่าง...Laragon ตรวจพบข้อผิดพลาด exception:
717 = ไม่สามารถสร้างฐานข้อมูล %s ได้ เหตุผล: %s
718 = ไม่สามารถเปลี่ยนรหัสผ่าน root ของ MySQL ได้ เหตุผล: %s
719 = คุณต้องระบุที่อยู่ Gmail ที่ถูกต้อง
720 = ไม่สามารถสร้างทางลัดในโฟลเดอร์ Startup ได้
721 = ไม่สามารถลบทางลัดจากโฟลเดอร์ Startup ได้
722 = รูปแบบไม่ถูกต้อง ต้องมีรูปแบบชื่อโปรเจกต์เป็น {name}.xxx
723 = รูปแบบไม่ถูกต้อง ไม่ใช่ชื่อโฮสต์ที่ถูกต้อง
724 = ไม่ใช่ Data Dir ของ MySQL ที่ถูกต้อง
725 = คุณต้องเปิดใช้งานเซอร์วิส Apache และ MySQL ใน เมนู > การตั้งค่า > เซอร์วิส & พอร์ต
# When Laragon cannot modify the hosts file
726 = อุ๊ปส์! ระบบของคุณป้องกันการแก้ไขไฟล์ hosts\nกรุณาตรวจสอบโปรแกรมป้องกันไวรัส หรือ Permissions ในแท็บ Security หรือตรวจสอบว่าไฟล์เป็นแบบอ่านอย่างเดียวหรือไม่\nLaragon จะปิดใช้งานฟีเจอร์ "สร้าง Virtual Hosts อัตโนมัติ" ชั่วคราว
727 = เพื่อให้ฟีเจอร์นี้ใช้งานได้ คุณสามารถลอง:\n1. ไปที่: %s\drivers\etc\n2. คลิกขวาที่ไฟล์ hosts และเอาเครื่องหมายถูกออกจากช่อง Read-only
728 = หมายเหตุ: Permissions ปัจจุบันของไฟล์ hosts:
# hosts file is Read-only
729 = อ่านอย่างเดียว
# Write permission in Security tab
730 = Security > Write
# MySQL
800 = ชื่อฐานข้อมูล
801 = รหัสผ่านใหม่
802 = รหัสผ่านปัจจุบัน
# Version 2
219 = Ngrok
220 = แชร์
221 = ลิงก์ Ngrok ถูกคัดลอกไปยังคลิปบอร์ดแล้ว
222 = Ngrok tunnel พร้อมแล้ว
223 = คลิกเพื่อแก้ไขไฟล์ hosts ในฐานะ Administrator ด้วยตนเอง
224 = เริ่มแล้ว
226 = กำลังคลายไฟล์
227 = คลายไฟล์แล้ว
228 = รูปแบบไม่รองรับ
229 = กรุณารอจนกว่าการแยกไฟล์จะเสร็จสมบูรณ์
230 = ลิงก์ไม่ถูกต้อง
231 = เกิดข้อผิดพลาดขณะดาวน์โหลด กรุณาลองอีกครั้ง
232 = เกิดข้อผิดพลาด บางทีลิงก์ดาวน์โหลดของคุณอาจไม่ถูกต้อง
233 = กรุณาตรวจสอบลิงก์และลองอีกครั้ง
234 = เยี่ยมชมเว็บไซต์
235 = ปิดและเยี่ยมชมเว็บไซต์
236 = แก้ไข
237 = สลับ Document Root
238 = เลือกอันอื่น
239 = มีฐานข้อมูลนี้อยู่แล้ว
240 = เว้นว่างไว้หากไม่ทราบ
241 = พอร์ต SSL ของ Apache ถูกปิดใช้งานโดยปริยาย ทำเครื่องหมายเพื่อเปิดใช้งาน
242 = สร้างใบรับรอง SSL แล้ว
243 = คุณต้องคลิก [%s] ก่อน
244 = สร้างฐานข้อมูลอัตโนมัติ
245 = วิธีบังคับให้ Wordpress ใช้ URL แบบสัมพัทธ์
246 = คลิกซ้าย
247 = คลิกขวา
248 = ที่ติดตั้ง Laragon
249 = ลบทั้งหมด [อัตโนมัติ]
250 = ไฟล์การตั้งค่า
251 = ไฟล์ Startup
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 ก่อน
810 = เริ่มเซิร์ฟเวอร์ MySQL ด้วยตัวเลือก %s
811 = กำลังรีเซ็ตรหัสผ่าน root และสร้างรหัสผ่านแบบสุ่ม
812 = รีเซ็ตและสร้างรหัสผ่าน root ของ MySQL แล้ว
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 && Terminal
832 = ลบ Sublime Text && Terminal
833 = แก้ไขด้วย Sublime Text
834 = เปิดโฟลเดอร์ใน Sublime Text
836 = กรุณารัน Laragon ในฐานะ Administrator แล้วลองอีกครั้ง
# Setup
900 = Laragon ทำงานเร็วมากและใช้หน่วยความจำน้อยมาก (< 10 MB)
901 = แอปของคุณจะได้รับ URL แบบอ่านง่าย ---> https://app.test
902 = เพิ่ม Sublime Text && Terminal ไปยังเมนูคลิกขวา
903 = วิธีเปิด Text Editor และ Command Prompt อย่างรวดเร็ว
904 = ดูไฟล์ README
905 = รัน Laragon
# SSL
906 = สร้างใบรับรอง SSL อัตโนมัติ
# Version 3
140 = กำลังเตรียมข้อมูลเริ่มต้น...
141 = ไม่สามารถเตรียมข้อมูลเริ่มต้นได้ โปรดลองอีกครั้ง
142 = ภูมิภาค
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 = โคลนฐานข้อมูลแล้ว
# version 7.0 Laragon 2025
927 = ลบโปรเจกต์
928 = โปรไฟล์
929 = โปรไฟล์ปัจจุบัน
930 = โปรไฟล์ใหม่
931 = ชื่อโปรไฟล์
932 = การดำเนินการ
940 = คุณต้องเปิดใช้งานและเริ่ม Mailpit
# version 8.0 Laragon 2025
168 = SSL ปิดใช้งานอยู่ คลิกเพื่อเปิดใช้งาน
360 = สำรองข้อมูลอัตโนมัติ
361 = Laragon จะสำรองข้อมูลในไดเรกทอรีข้อมูลของคุณโดยอัตโนมัติทุก 8 ชั่วโมง โดยจัดเก็บข้อมูลสำรองไว้ใน %s และเก็บเวอร์ชันล่าสุด 5 เวอร์ชันไว้เพื่อความปลอดภัย
362 = ช่วงเวลาสำรองข้อมูล
363 = ชั่วโมง
380 = อัปเดตอัตโนมัติ
381 = Laragon จะตรวจสอบ ดาวน์โหลด และกำหนดค่า PHP เวอร์ชันล่าสุดโดยอัตโนมัติ ทำให้สภาพแวดล้อมทันสมัยอยู่เสมออย่างง่ายดาย
382 = %s [%s] เวอร์ชันล่าสุดถูกเพิ่มไปยัง Laragon แล้ว
383 = %s [%s] มีเวอร์ชันใหม่พร้อมใช้งาน
260 = คัดลอกรหัสผ่าน root
261 = สำรองข้อมูลทุกฐานข้อมูล
262 = ฐานข้อมูล MySQL ทั้งหมดถูกสำรองไปยัง %s เรียบร้อยแล้ว
263 = รหัสผ่าน root ของ MySQL ถูกคัดลอกไปยังคลิปบอร์ดแล้ว

View File

@@ -1,10 +1,10 @@
Alias /adminer "C:/laragon/etc/apps/adminer/"
# to give access from outside
# to give access from outside
# replace the lines
#
# Require local
#
#
# by
#
# Require all granted
@@ -12,8 +12,8 @@ Alias /adminer "C:/laragon/etc/apps/adminer/"
<Directory "C:/laragon/etc/apps/adminer/">
Options Indexes FollowSymLinks MultiViews
AllowOverride all
AllowOverride all
Require local
</Directory>

View File

@@ -1,10 +1,10 @@
Alias /laragon "C:/laragon/etc/apps/laragon/"
# to give access from outside
# to give access from outside
# replace the lines
#
# Require local
#
#
# by
#
# Require all granted
@@ -12,18 +12,18 @@ Alias /laragon "C:/laragon/etc/apps/laragon/"
<Directory "C:/laragon/etc/apps/laragon/">
Options Indexes FollowSymLinks MultiViews
AllowOverride None
AllowOverride None
Require local
</Directory>
<Directory "C:/laragon/etc/apps/laragon/uploads/">
Options Indexes FollowSymLinks MultiViews
AllowOverride None
AllowOverride None
DirectoryIndex None.Always.Listing
Require local
SetHandler none
SetHandler default-handler

View File

@@ -1,9 +1,9 @@
Alias /memcached "C:/laragon/etc/apps/memcached/"
# to give access from outside
# to give access from outside
# replace the lines
#
# Require local
# Require local
#
# by
#
@@ -13,7 +13,7 @@ Alias /memcached "C:/laragon/etc/apps/memcached/"
<Directory "C:/laragon/etc/apps/memcached/">
Options Indexes FollowSymLinks MultiViews
AllowOverride all
Require local
</Directory>

View File

@@ -1,10 +1,10 @@
Alias /phpmyadmin "C:/laragon/etc/apps/phpMyAdmin/"
# to give access from outside
# to give access from outside
# replace the lines
#
# Require local
#
#
# by
#
# Require all granted
@@ -12,8 +12,8 @@ Alias /phpmyadmin "C:/laragon/etc/apps/phpMyAdmin/"
<Directory "C:/laragon/etc/apps/phpMyAdmin/">
Options Indexes FollowSymLinks MultiViews
AllowOverride all
AllowOverride all
Require local
</Directory>

View File

@@ -1,9 +1,9 @@
Alias /redis "C:/laragon/etc/apps/phpredisAdmin/"
# to give access from outside
# to give access from outside
# replace the lines
#
# Require local
# Require local
#
# by
#
@@ -13,7 +13,7 @@ Alias /redis "C:/laragon/etc/apps/phpredisAdmin/"
<Directory "C:/laragon/etc/apps/phpredisAdmin/">
Options Indexes FollowSymLinks MultiViews
AllowOverride all
Require local
</Directory>

View File

@@ -8,7 +8,7 @@ FcgidInitialEnv TEMP "C:/Windows/Temp"
FcgidInitialEnv TMP "C:/Windows/Temp"
FcgidInitialEnv windir "C:/Windows"
# 10 hrs: in case you have long running scripts, increase FcgidIOTimeout
# 10 hrs: in case you have long running scripts, increase FcgidIOTimeout
FcgidIOTimeout 36000
FcgidConnectTimeout 16
FcgidMaxRequestsPerProcess 0

View File

@@ -5,7 +5,7 @@ SSLCipherSuite HIGH:MEDIUM:!MD5:!RC4
SSLProxyCipherSuite HIGH:MEDIUM:!MD5:!RC4
SSLHonorCipherOrder on
SSLHonorCipherOrder on
SSLProtocol all -SSLv3
SSLProxyProtocol all -SSLv3
@@ -13,5 +13,3 @@ SSLProxyProtocol all -SSLv3
SSLSessionCache "shmcb:logs/ssl_scache(512000)"
SSLSessionCacheTimeout 300

File diff suppressed because one or more lines are too long

View File

@@ -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.

View File

@@ -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 &mdash; 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

View File

@@ -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;
}
}

File diff suppressed because one or more lines are too long

View File

@@ -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;
}

View File

@@ -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;
}
}

View File

@@ -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));

View File

@@ -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));

View File

@@ -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));

View File

@@ -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, '&amp;' )
.replace( /"/g, '&quot;' )
.replace( /'/g, '&#39;' )
.replace( /</g, '&lt;' )
.replace( />/g, '&gt;' );
}
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>

View File

@@ -1 +0,0 @@
Antony Dovgal, Mikael Johansson

View File

@@ -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>.

View File

@@ -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

View File

@@ -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";
}
?>

View File

@@ -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 &amp; 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">&nbsp;</span>Free: ',bsize($mem_avail).sprintf(" (%.1f%%)",$mem_avail*100/$mem_size),"</td>\n",
'<td class=td-1><span class="green box">&nbsp;</span>Hits: ',$hits.sprintf(" (%.1f%%)",$hits*100/($hits+$misses)),"</td>\n",
'</tr>',
'<tr>',
'<td class=td-0><span class="red box">&nbsp;</span>Used: ',bsize($mem_used ).sprintf(" (%.1f%%)",$mem_used *100/$mem_size),"</td>\n",
'<td class=td-1><span class="red box">&nbsp;</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.

View File

@@ -38,14 +38,14 @@ if exist "%USER_DIR%\user.cmd" (
echo :: call start-ssh-agent.cmd
echo :: set PATH=%%USER_DIR%%\bin\whatever;%%PATH%%
echo.
echo :: cmd /c start http://localhost
echo :: cmd /c start http://localhost
echo.
) > "%USER_DIR%\user.cmd"
:: cd /d "%CMDER_ROOT%\..\..\www"
rem
)
:: Laragon End -------------------------------------------------------------------
exit /b 0

View File

@@ -6,7 +6,7 @@ location /adminer {
location ~ ^/adminer/(.+\.php)$ {
alias C:/laragon/etc/apps/adminer/$1;
fastcgi_pass php_upstream;
fastcgi_pass php_upstream;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $request_filename;

View File

@@ -12,7 +12,7 @@ location ~ /laragon/uploads/(.+)\.php$ {
location ~ ^/laragon/(.+\.php)$ {
allow all;
alias C:/laragon/etc/apps/laragon/$1;
fastcgi_pass php_upstream;
fastcgi_pass php_upstream;
fastcgi_index index.php;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_param SCRIPT_FILENAME $request_filename;

View File

@@ -3,10 +3,10 @@ location /memcached {
alias C:/laragon/etc/apps/memcached/;
index index.php;
}
location ~ ^/memcached/(.+\.php)$ {
alias C:/laragon/etc/apps/memcached/$1;
fastcgi_pass php_upstream;
fastcgi_pass php_upstream;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $request_filename;

View File

@@ -3,12 +3,12 @@ location /phpmyadmin {
alias C:/laragon/etc/apps/phpmyadmin/;
index index.php;
}
location ~ ^/phpmyadmin/(.+\.php)$ {
alias C:/laragon/etc/apps/phpmyadmin/$1;
fastcgi_pass php_upstream;
fastcgi_pass php_upstream;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $request_filename;

View File

@@ -6,7 +6,7 @@ location /redis {
location ~ ^/redis/(.+\.php)$ {
alias C:/laragon/etc/apps/phpRedisAdmin/$1;
fastcgi_pass php_upstream;
fastcgi_pass php_upstream;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $request_filename;

View File

@@ -173,9 +173,9 @@ class Memcached
protected $socket = null;
public function getVersion() {
return ['localhost:11211' => '1.4.5'];
return ['localhost:11211' => '1.4.5'];
}
//may check: https://raw.githubusercontent.com/GoogleCloudPlatform/python-compat-runtime/master/appengine-compat/exported_appengine_sdk/php/sdk/google/appengine/runtime/Memcached.php
public function setMulti() {
@@ -185,7 +185,7 @@ class Memcached
//TODO
die('TODO');
}
/**
* Add a serer to the server pool
*
@@ -444,7 +444,7 @@ class Memcached
/**
* Store an item.
* Store an item.
* Fails if $key already exists
*
* @param string $key
@@ -464,7 +464,7 @@ class Memcached
if ('STORED' == $s) {
$this->resultCode = Memcached::RES_SUCCESS;
$this->resultMessage = '';
$this->resultMessage = '';
return true;
} else {

Binary file not shown.

View File

@@ -9,7 +9,6 @@
; PWD: Current working directory - where the COMMANDS run
# Examples:
; My Cool App: autorun node start $PORT PORT=9000 env_file=usr\my_file.env PWD=usr/proj/myapp DB_HOST=1.2.3.4 DB_PORT=9999 DB_USER=user DB_PASS="!$Ab.cs3cre1" DB_NAME=cooldb
; My Cool App: autorun node start $PORT PORT=9000 env_file=usr\my_file.env PWD=usr/proj/myapp DB_HOST=1.2.3.4 DB_PORT=9999 DB_USER=user DB_PASS="!$Ab.cs3cre1" DB_NAME=cooldb
; Awesome Tool: "PATH HAS SPACES SHOULD BE QUOTED LIKE THIS"
------------------------------------------------------------------------------

View File

@@ -9,7 +9,6 @@
; PWD: Current working directory - where the COMMANDS run
# Examples:
; My Cool App: autorun node start $PORT PORT=9000 env_file=usr\my_file.env PWD=usr/proj/myapp DB_HOST=1.2.3.4 DB_PORT=9999 DB_USER=user DB_PASS="!$Ab.cs3cre1" DB_NAME=cooldb
; My Cool App: autorun node start $PORT PORT=9000 env_file=usr\my_file.env PWD=usr/proj/myapp DB_HOST=1.2.3.4 DB_PORT=9999 DB_USER=user DB_PASS="!$Ab.cs3cre1" DB_NAME=cooldb
; Awesome Tool: "PATH HAS SPACES SHOULD BE QUOTED LIKE THIS"
------------------------------------------------------------------------------

View File

@@ -1,25 +1,33 @@
# PHP
# https://windows.php.net/download/
# NTS = Non Thread Safe
*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
# NTS = Non Thread Safe
*PHP-8.4=https://windows.php.net/downloads/releases/archives/php-8.4.3-nts-Win32-vs17-x64.zip
*PHP-8.3=https://windows.php.net/downloads/releases/archives/php-8.3.16-nts-Win32-vs16-x64.zip
*PHP-8.2=https://windows.php.net/downloads/releases/archives/php-8.2.26-nts-Win32-vs16-x64.zip
*PHP-8.1=https://windows.php.net/downloads/releases/archives/php-8.1.30-nts-Win32-vs16-x64.zip
---
# Web Servers
Apache-2.4.63=https://www.apachelounge.com/download/VS17/binaries/httpd-2.4.63-250122-win64-VS17.zip
Apache-2.4.57=https://www.apachelounge.com/download/VS16/binaries/httpd-2.4.57-win64-VS16.zip
Nginx-1.27.4=https://nginx.org/download/nginx-1.27.4.zip
---
# Node.js
# https://nodejs.org/en/download/prebuilt-binaries/current
node-23=https://nodejs.org/dist/v23.4.0/node-v23.4.0-win-x64.zip
node-22=https://nodejs.org/dist/v22.12.0/node-v22.12.0-win-x64.zip
node-23.9=https://nodejs.org/dist/v23.9.0/node-v23.9.0-win-x64.zip
node-22.14=https://nodejs.org/dist/v22.14.0/node-v22.14.0-win-x64.zip
---
# phpMyAdmin
# After download, visit -> http://localhost/phpmyadmin
phpmyadmin=https://files.phpmyadmin.net/phpMyAdmin/5.2.1/phpMyAdmin-5.2.1-all-languages.zip
phpmyadmin-6.0snapshot=https://files.phpmyadmin.net/snapshots/phpMyAdmin-6.0+snapshot-english.tar.xz
phpmyadmin=https://files.phpmyadmin.net/phpMyAdmin/5.2.2/phpMyAdmin-5.2.2-english.zip
# DB Tools
DBeaver=https://dbeaver.io/files/dbeaver-ce-latest-win32.win32.x86_64.zip
@@ -43,7 +51,7 @@ postgresql-15.10=https://sbp.enterprisedb.com/getfile.jsp?fileid=1259300
---
# MongoDB
# MongoDB
# https://www.mongodb.com/try/download/community
#mongodb-8=https://fastdl.mongodb.org/windows/mongodb-windows-x86_64-8.0.4.zip
#mongodb-7=https://fastdl.mongodb.org/windows/mongodb-windows-x86_64-7.0.14.zip
@@ -56,8 +64,10 @@ code=https://go.microsoft.com/fwlink/?Linkid=850641
---
# Golang
# https://go.dev/dl/
golang-1.23=https://go.dev/dl/go1.23.4.windows-amd64.zip
go-1.24=https://go.dev/dl/go1.24.1.windows-amd64.zip
go-1.23=https://go.dev/dl/go1.23.4.windows-amd64.zip
# Pocketbase
# https://github.com/pocketbase/pocketbase/releases
pocketbase=https://github.com/pocketbase/pocketbase/releases/download/v0.23.7/pocketbase_0.23.7_windows_amd64.zip
pocketbase=https://github.com/pocketbase/pocketbase/releases/download/v0.25.9/pocketbase_0.25.9_windows_amd64.zip

View File

@@ -1,15 +1,15 @@
Simplicity is the ultimate sophistication. - Leonardo da Vinci
Success is going from failure to failure without losing your enthusiasm. - Winston Churchill
Success is going from failure to failure without losing your enthusiasm. - Winston Churchill
The journey of a thousand miles begins with one step. - Lao Tzu
Dream big and dare to fail. - Norman Vaughan
Dream big and dare to fail. - Norman Vaughan
The power of imagination makes us infinite. - John Muir
Make each day your masterpiece. - John Wooden
Believe and act as if it were impossible to fail. - Charles Kettering
Make each day your masterpiece. - John Wooden
Believe and act as if it were impossible to fail. - Charles Kettering
Light tomorrow with today. - Elizabeth Barrett Browning
Even if you're on the right track, you'll get run over if you just sit there. - Will Rogers
Even if you're on the right track, you'll get run over if you just sit there. - Will Rogers
Believe you can and you're halfway there. - Theodore Roosevelt
Don't wait. The time will never be just right. - Napoleon Hill
A year from now you may wish you had started today. - Karen Lamb
Don't wait. The time will never be just right. - Napoleon Hill
A year from now you may wish you had started today. - Karen Lamb
It is never too late to be what you might have been. - George Eliot
If there is no struggle, there is no progress. - Frederick Douglass
What we fear doing most is usually what we most need to do. - Tim Ferriss

View File

@@ -2,5 +2,32 @@
AutoCreateDatabase=true
Cached=true
# Blank: an empty project
Blank=
# WordPress
WordPress=https://wordpress.org/latest.zip
WordPress=https://wordpress.org/latest.tar.gz
------------------------------------------------------
# Laravel
Laravel=composer create-project laravel/laravel %s --prefer-dist
Laravel CLI=laravel new %s
# Laravel (zip)=PATH-TO-YOUR-ZIP
------------------------------------------------------
# CakePHP
### CakePHP=composer create-project --prefer-dist cakephp/app %s
# Symfony
Symfony=composer create-project symfony/website-skeleton %s

View File

@@ -1,167 +1,105 @@
<?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;
}
.info {
margin-top: 20px;
font-size: 18px;
line-height: 1.6;
}
.header--logo {
height: 8rem;
}
.info a {
color: #007bff;
text-decoration: none;
}
h1 {
font-size: 5rem;
}
.info a:hover {
color: #0056b3;
text-decoration: underline;
}
main {
background-color: #f5f5f5;
}
.opt {
margin-top: 30px;
}
nav {
width: 100%;
}
.opt a {
font-size: 18px;
color: #007bff;
text-decoration: none;
}
ul {
list-style: none;
padding: 0;
margin: auto;
}
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>