Compare commits
36 Commits
7.0.2
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b0885989e4 | ||
|
|
00d8a84e16 | ||
|
|
fee18b42db | ||
|
|
11e3ffc1d2 | ||
|
|
cf4bcd6d9f | ||
|
|
df3d72b936 | ||
|
|
5d48b71858 | ||
|
|
75a4430457 | ||
|
|
705c0da87b | ||
|
|
6a9a83fb47 | ||
|
|
593338f8f8 | ||
|
|
f403e94463 | ||
|
|
ec467a6f33 | ||
|
|
4b7289618f | ||
|
|
b716689318 | ||
|
|
b99af56576 | ||
|
|
45219c7b39 | ||
|
|
98a6ced6b0 | ||
|
|
620dc8bc72 | ||
|
|
3ad0d09569 | ||
|
|
9fdd698e09 | ||
|
|
ea6254fc80 | ||
|
|
566be5ce9f | ||
|
|
959aab1bc7 | ||
|
|
3f0534e0e1 | ||
|
|
6d0ca768f9 | ||
|
|
1bf6169ffc | ||
|
|
6959b13189 | ||
|
|
2631fda37b | ||
|
|
3fcd32d767 | ||
|
|
b371252f27 | ||
|
|
18992b2d5c | ||
|
|
5cf5f6b2ae | ||
|
|
45d2c3f117 | ||
|
|
f58e47d630 | ||
|
|
b23f970bea |
223
.github/copilot-instructions.md
vendored
Normal file
223
.github/copilot-instructions.md
vendored
Normal 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
1
CHANGELOG.md
Normal file
@@ -0,0 +1 @@
|
|||||||
|
https://github.com/leokhoa/laragon/releases
|
||||||
10
README.md
10
README.md
@@ -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 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.
|
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!
|
Enjoy!
|
||||||
|
|
||||||
|
> Starting with Laragon 7.x, a license is required to use Laragon. For more details, visit <https://laragon.lemonsqueezy.com/>.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Pretty URLs**
|
- **Pretty URLs**
|
||||||
Use `app.test` instead of `localhost/app`.
|
Use `app.test` instead of `localhost/app`.
|
||||||
- **Portable**
|
- **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**
|
- **Isolated**
|
||||||
Laragon has an isolated environment with your OS - it will keep your system clean.
|
Laragon has an isolated environment with your OS - it will keep your system clean.
|
||||||
- **Easy Operation**
|
- **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.
|
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:
|
Also, Laragon makes things a lot easier:
|
||||||
- Wanna have a Wordpress CMS? Just 1 click.
|
- 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.
|
- Wanna enable/disable a PHP extension? Just 1 click.
|
||||||
|
|
||||||
|
|
||||||
@@ -37,7 +39,7 @@ Enjoy!
|
|||||||
## How fast?
|
## How fast?
|
||||||
Laragon starts instantly. You can set Laragon autorun when Windows starts. When running, Laragon uses just a little amount of your RAM.
|
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:
|
Here is the GUI of Laragon:
|
||||||

|

|
||||||
|
|
||||||
## How easy?
|
## How easy?
|
||||||
- Laragon is very easy to install & upgrade. Just download the latest version and click `Next, Next, Next...`
|
- Laragon is very easy to install & upgrade. Just download the latest version and click `Next, Next, Next...`
|
||||||
|
|||||||
13
SECURITY.md
Normal file
13
SECURITY.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
| Version | Supported |Reason |
|
||||||
|
| ------- | ------------------ | ---------- |
|
||||||
|
| >=7.0 | :white_check_mark: | |
|
||||||
|
| <=6.0 | :x: | EOL |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
If you find a security vulnerability in Laragon, please report it via email to Leo Khoa at leo@laragon.org
|
||||||
|
We take security seriously, and all reports will be promptly addressed.
|
||||||
321
bin/laragon/lang/Thai.txt
Normal file
321
bin/laragon/lang/Thai.txt
Normal 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 ถูกคัดลอกไปยังคลิปบอร์ดแล้ว
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
Alias /adminer "C:/laragon/etc/apps/adminer/"
|
Alias /adminer "C:/laragon/etc/apps/adminer/"
|
||||||
|
|
||||||
# to give access from outside
|
# to give access from outside
|
||||||
# replace the lines
|
# replace the lines
|
||||||
#
|
#
|
||||||
# Require local
|
# Require local
|
||||||
#
|
#
|
||||||
# by
|
# by
|
||||||
#
|
#
|
||||||
# Require all granted
|
# Require all granted
|
||||||
@@ -12,8 +12,8 @@ Alias /adminer "C:/laragon/etc/apps/adminer/"
|
|||||||
|
|
||||||
<Directory "C:/laragon/etc/apps/adminer/">
|
<Directory "C:/laragon/etc/apps/adminer/">
|
||||||
Options Indexes FollowSymLinks MultiViews
|
Options Indexes FollowSymLinks MultiViews
|
||||||
AllowOverride all
|
AllowOverride all
|
||||||
|
|
||||||
Require local
|
Require local
|
||||||
|
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
Alias /laragon "C:/laragon/etc/apps/laragon/"
|
Alias /laragon "C:/laragon/etc/apps/laragon/"
|
||||||
|
|
||||||
# to give access from outside
|
# to give access from outside
|
||||||
# replace the lines
|
# replace the lines
|
||||||
#
|
#
|
||||||
# Require local
|
# Require local
|
||||||
#
|
#
|
||||||
# by
|
# by
|
||||||
#
|
#
|
||||||
# Require all granted
|
# Require all granted
|
||||||
@@ -12,18 +12,18 @@ Alias /laragon "C:/laragon/etc/apps/laragon/"
|
|||||||
|
|
||||||
<Directory "C:/laragon/etc/apps/laragon/">
|
<Directory "C:/laragon/etc/apps/laragon/">
|
||||||
Options Indexes FollowSymLinks MultiViews
|
Options Indexes FollowSymLinks MultiViews
|
||||||
AllowOverride None
|
AllowOverride None
|
||||||
|
|
||||||
Require local
|
Require local
|
||||||
|
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|
||||||
<Directory "C:/laragon/etc/apps/laragon/uploads/">
|
<Directory "C:/laragon/etc/apps/laragon/uploads/">
|
||||||
Options Indexes FollowSymLinks MultiViews
|
Options Indexes FollowSymLinks MultiViews
|
||||||
AllowOverride None
|
AllowOverride None
|
||||||
DirectoryIndex None.Always.Listing
|
DirectoryIndex None.Always.Listing
|
||||||
Require local
|
Require local
|
||||||
|
|
||||||
SetHandler none
|
SetHandler none
|
||||||
SetHandler default-handler
|
SetHandler default-handler
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
Alias /memcached "C:/laragon/etc/apps/memcached/"
|
Alias /memcached "C:/laragon/etc/apps/memcached/"
|
||||||
|
|
||||||
# to give access from outside
|
# to give access from outside
|
||||||
# replace the lines
|
# replace the lines
|
||||||
#
|
#
|
||||||
# Require local
|
# Require local
|
||||||
#
|
#
|
||||||
# by
|
# by
|
||||||
#
|
#
|
||||||
@@ -13,7 +13,7 @@ Alias /memcached "C:/laragon/etc/apps/memcached/"
|
|||||||
<Directory "C:/laragon/etc/apps/memcached/">
|
<Directory "C:/laragon/etc/apps/memcached/">
|
||||||
Options Indexes FollowSymLinks MultiViews
|
Options Indexes FollowSymLinks MultiViews
|
||||||
AllowOverride all
|
AllowOverride all
|
||||||
|
|
||||||
Require local
|
Require local
|
||||||
|
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
Alias /phpmyadmin "C:/laragon/etc/apps/phpMyAdmin/"
|
Alias /phpmyadmin "C:/laragon/etc/apps/phpMyAdmin/"
|
||||||
|
|
||||||
# to give access from outside
|
# to give access from outside
|
||||||
# replace the lines
|
# replace the lines
|
||||||
#
|
#
|
||||||
# Require local
|
# Require local
|
||||||
#
|
#
|
||||||
# by
|
# by
|
||||||
#
|
#
|
||||||
# Require all granted
|
# Require all granted
|
||||||
@@ -12,8 +12,8 @@ Alias /phpmyadmin "C:/laragon/etc/apps/phpMyAdmin/"
|
|||||||
|
|
||||||
<Directory "C:/laragon/etc/apps/phpMyAdmin/">
|
<Directory "C:/laragon/etc/apps/phpMyAdmin/">
|
||||||
Options Indexes FollowSymLinks MultiViews
|
Options Indexes FollowSymLinks MultiViews
|
||||||
AllowOverride all
|
AllowOverride all
|
||||||
|
|
||||||
Require local
|
Require local
|
||||||
|
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
Alias /redis "C:/laragon/etc/apps/phpredisAdmin/"
|
Alias /redis "C:/laragon/etc/apps/phpredisAdmin/"
|
||||||
|
|
||||||
# to give access from outside
|
# to give access from outside
|
||||||
# replace the lines
|
# replace the lines
|
||||||
#
|
#
|
||||||
# Require local
|
# Require local
|
||||||
#
|
#
|
||||||
# by
|
# by
|
||||||
#
|
#
|
||||||
@@ -13,7 +13,7 @@ Alias /redis "C:/laragon/etc/apps/phpredisAdmin/"
|
|||||||
<Directory "C:/laragon/etc/apps/phpredisAdmin/">
|
<Directory "C:/laragon/etc/apps/phpredisAdmin/">
|
||||||
Options Indexes FollowSymLinks MultiViews
|
Options Indexes FollowSymLinks MultiViews
|
||||||
AllowOverride all
|
AllowOverride all
|
||||||
|
|
||||||
Require local
|
Require local
|
||||||
|
|
||||||
</Directory>
|
</Directory>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ FcgidInitialEnv TEMP "C:/Windows/Temp"
|
|||||||
FcgidInitialEnv TMP "C:/Windows/Temp"
|
FcgidInitialEnv TMP "C:/Windows/Temp"
|
||||||
FcgidInitialEnv windir "C:/Windows"
|
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
|
FcgidIOTimeout 36000
|
||||||
FcgidConnectTimeout 16
|
FcgidConnectTimeout 16
|
||||||
FcgidMaxRequestsPerProcess 0
|
FcgidMaxRequestsPerProcess 0
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ SSLCipherSuite HIGH:MEDIUM:!MD5:!RC4
|
|||||||
SSLProxyCipherSuite HIGH:MEDIUM:!MD5:!RC4
|
SSLProxyCipherSuite HIGH:MEDIUM:!MD5:!RC4
|
||||||
|
|
||||||
|
|
||||||
SSLHonorCipherOrder on
|
SSLHonorCipherOrder on
|
||||||
|
|
||||||
SSLProtocol all -SSLv3
|
SSLProtocol all -SSLv3
|
||||||
SSLProxyProtocol all -SSLv3
|
SSLProxyProtocol all -SSLv3
|
||||||
@@ -13,5 +13,3 @@ SSLProxyProtocol all -SSLv3
|
|||||||
|
|
||||||
SSLSessionCache "shmcb:logs/ssl_scache(512000)"
|
SSLSessionCache "shmcb:logs/ssl_scache(512000)"
|
||||||
SSLSessionCacheTimeout 300
|
SSLSessionCacheTimeout 300
|
||||||
|
|
||||||
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -1,198 +0,0 @@
|
|||||||
Change Log
|
|
||||||
============================
|
|
||||||
### Version 2.0 ###
|
|
||||||
|
|
||||||
SimpleAjaxUploader.js:
|
|
||||||
|
|
||||||
* Added support for drag and drop file uploads
|
|
||||||
* Added `ss.uploadSetup()` method to set default uploader option values (useful for multiple uploader instances)
|
|
||||||
* Added `noParams` option to disable the default behavior of appending the file name to the URL query string
|
|
||||||
* Numerous code improvements throughout -- bug fixes, memory usage, etc.
|
|
||||||
|
|
||||||
Uploader.php
|
|
||||||
* Refactored into a single class in accordance with one class, one file
|
|
||||||
* Made improvements to error detection and handling
|
|
||||||
* Added support for reading the `X-File-Name` header as an alternative to query string parameters for sending file names to the server
|
|
||||||
* Set default value of the `$uploadName` property to be `"uploadfile"` for consistency with the examples - <a href="https://github.com/LPology/Simple-Ajax-Uploader/issues/72">72</a>
|
|
||||||
|
|
||||||
### Version 1.11 ###
|
|
||||||
* Added support for PHP Session Upload Progress for PHP 5.4+ (APC was deprecated in 5.3)
|
|
||||||
* Added `clearQueue()` method which gives the user the ability to clear all files in queue - <a href="https://github.com/LPology/Simple-Ajax-Uploader/pull/62">#62</a> - (Special thanks to <a href="https://github.com/mouse0270">mouse0270</a> for this one)
|
|
||||||
* Fixed multiple file selection bug - <a href="https://github.com/LPology/Simple-Ajax-Uploader/pull/67">#67</a> - (Special thanks to <a href="https://github.com/genintho">genintho</a> for this)
|
|
||||||
* Fixed bug which could allow form/input elements to be created with invalid name/ID attributes in IE7-9
|
|
||||||
|
|
||||||
### Version 1.10.1 ###
|
|
||||||
* `iframe` and `form` elements are now created with `document.createElement()` rather than the much slower HTML injection method
|
|
||||||
* Removed unused variable from `_uploadIframe()`
|
|
||||||
|
|
||||||
### Version 1.10 ###
|
|
||||||
* Added `setOptions()` method for setting or changing upload options - <a href="https://github.com/LPology/Simple-Ajax-Uploader/issues/54">#54</a> - (special thanks to <a href="https://github.com/hauru">hauru</a> for this)
|
|
||||||
* Added `customHeader` option for sending custom request headers - <a href="https://github.com/LPology/Simple-Ajax-Uploader/issues/47">#47</a> (special thanks to <a href="https://github.com/cillosis">cillosis</a> for this)
|
|
||||||
* Updated `ss.parseJSON()` to use a more secure method of manually parsing JSON
|
|
||||||
|
|
||||||
### Version 1.9.1 ###
|
|
||||||
* `onError()` callback now receives server response as an argument, if it exists, or `false` if it does not - <a href="https://github.com/LPology/Simple-Ajax-Uploader/pull/37">#37</a> (special thanks to <a href="https://github.com/KSDaemon">KSDaemon</a> for this)
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
<strong>API Change Note:</strong> For consistency with the other callbacks, the server response is passed to `onError()` as the next to last argument, directly before the upload button. Therefore, if you use the upload button parameter in `onError()`, you will need to update your code when upgrading.
|
|
||||||
<br />
|
|
||||||
<br />
|
|
||||||
* Switched from Google Closure Compiler to YUI Compressor for minification
|
|
||||||
|
|
||||||
### Version 1.9 ###
|
|
||||||
* Added CORS support - <a href="http://www.lpology.com/code/ajaxuploader/How-to-Cross-Domain-File-Uploading.php">Learn more</a>
|
|
||||||
* Query string parameters for Nginx Upload Progress Module in `_uploadIframe()` are now encoded with `encodeURIComponent()`
|
|
||||||
* Upload progress ID keys are now generated prior to each upload instead of on page load
|
|
||||||
* Query string parameters passed to `url` are now preserved - <a href="https://github.com/LPology/Simple-Ajax-Uploader/issues/34">#34</a> (special thanks to <a href="https://github.com/Deefjuh">Deefjuh</a> for this)
|
|
||||||
|
|
||||||
### Version 1.8.2 ###
|
|
||||||
* A reference to the button which triggers an upload is now passed as the last argument to the following callbacks: `onAbort()`, `onChange()`, `onSubmit()`, `onComplete()`, `onError()`, `startXHR()`, `endXHR()`, `startNonXHR()`, `endNonXHR()` (can be useful when using multiple upload buttons)
|
|
||||||
* Fixed bug which caused some methods to not work if called inside of `startXHR()` or `startNonXHR()`
|
|
||||||
* Fixed bug causing undefined variable in IE9 and older if `progressUrl` and `nginxProgressUrl` are not set
|
|
||||||
|
|
||||||
### Version 1.8.1 ###
|
|
||||||
* Added `destroy()` method for completely removing upload functionality
|
|
||||||
* Removed redundant call to `ss.verifyElem()` inside of `rerouteClicks()`
|
|
||||||
* Moved browser-specific checks to top of IIFE, as they only need to execute once
|
|
||||||
|
|
||||||
### Version 1.8 ###
|
|
||||||
SimpleAjaxUploader.js:
|
|
||||||
* Added support for <a href="http://wiki.nginx.org/HttpUploadProgressModule">Nginx Upload Progress Module</a>
|
|
||||||
* Added `setAbortBtn()` method to designate an element as "cancel" button
|
|
||||||
* Added `onAbort()` callback function to specify behavior upon manual abort
|
|
||||||
* Added `setPctBox()` method to designate an element to be injected with upload progress percentage
|
|
||||||
* Switched to a unique ID function that is RFC 4122 version 4 compliant
|
|
||||||
* The `button` option now accepts either a single button (element ID string, element, or jQuery object), or an array of buttons. If an array is passed, each element in the array will work as an upload button
|
|
||||||
* Upload progress update request keys are now locally generated
|
|
||||||
* Fixed bug that was causing `onError()` to be fired twice
|
|
||||||
* For consistency with jQuery behavior, any 2xx status code is now handled as a successful response (previously, only `200` and `201` were successful)
|
|
||||||
* Upload buttons are now being properly disabled/enabled at correct points
|
|
||||||
* Made significant improvements to error handling, particularly with iframe uploads and retrieving server provided progress updates
|
|
||||||
* Fixed a number of potential memory leaks for Internet Explorer
|
|
||||||
* Regular expressions are now pre-compiled and cached for better performance
|
|
||||||
* For server progress tracking, `sizeBox` and `onUpdateFileSize()` are no longer pointlessly set/called again after first progress update is received
|
|
||||||
|
|
||||||
uploadProgress.php:
|
|
||||||
* Removed functionality for returning upload keys, as RFC 4122 v4 compliant UUIDs are now generated client side
|
|
||||||
|
|
||||||
### Version 1.7 ###
|
|
||||||
SimpleAjaxUploader.js:
|
|
||||||
* Fixed IE6/IE7 memory leak when removing elements without first removing event listeners (<a href="https://github.com/LPology/Simple-Ajax-Uploader/issues/21">issue #21</a>)
|
|
||||||
* Fixed possible race condition in which `removeCurrent()` could potentially delete the wrong file from the upload queue
|
|
||||||
* Multiple file inputs are now disabled in Safari due to a browser bug that just screws everything up (see: http://stackoverflow.com/q/7231054/1091949)
|
|
||||||
* Switched to a smaller, faster process for cross-browser bounding box calculation
|
|
||||||
* Updated to faster methods of checking for, adding, and removing element CSS classes
|
|
||||||
* Combined `_checkExtension()` with `_checkFile()` to eliminate a function call/reduce code size
|
|
||||||
* Combined `_handleIframeResponse()` with `_uploadIframe()` and switched to a more efficient method of getting iframe contents
|
|
||||||
* Removed a number of unnecessary/redundant function calls, along with some unnecessary variable copying
|
|
||||||
* Updated `ss.verifyElem()` to use the much faster `charAt()` and `substr()` in place of a regex and `slice()`
|
|
||||||
* Added separate feature detection for file input `accept` attribute
|
|
||||||
|
|
||||||
Uploader.php:
|
|
||||||
* Removed unnecessary check of `$allowedExtensions` for `null` value in `handleUpload()`
|
|
||||||
* Added `final` keyword to `FileUploadXHR` and `FileUploadPOSTForm` classes and their respective methods to discourage direct use
|
|
||||||
|
|
||||||
### Version 1.6.5 ###
|
|
||||||
* When using `multipart`, additional data will now also appended to the multipart form.
|
|
||||||
* Cleaned up some messy code -- organization, unnecessary variable copying, etc.
|
|
||||||
|
|
||||||
### Version 1.6.4 ###
|
|
||||||
* Switched from using `setAttribute` to dot notation for setting element properties (some versions of IE don't handle `setAttribute` well)
|
|
||||||
* `ss.removeItem()` now uses the faster countdown method to loop through arrays
|
|
||||||
* In accordance with W3 standards, `_uploadXhr()` now accepts either a `200 OK` or `201 Created` as a successful response
|
|
||||||
* Uploader.php -- the `handleUpload()` method now checks whether the `allowedExtensions` property is `empty` instead of `null`. This prevents an "Invalid file type" error resulting from passing an empty array
|
|
||||||
|
|
||||||
### Version 1.6.3 ###
|
|
||||||
* Fixed bug which allowed `onComplete()` to be called after JSON parse error
|
|
||||||
|
|
||||||
### Version 1.6.2 ###
|
|
||||||
* Overhauled error handling to fix a number of issues.
|
|
||||||
* Added consistent error types for `onError()` so that the second parameter will be either:
|
|
||||||
`parseerror` (bad JSON from server), `transfererror` (xfer error during XHR upload), `servererror` (server response not `200 OK`)
|
|
||||||
* Fixed problem with null file size parameter for `endXHR()` callback
|
|
||||||
|
|
||||||
### Version 1.6.1 ###
|
|
||||||
* Plugin is now wrapped in an IIFE
|
|
||||||
* Leading semicolon added to close any previous statement
|
|
||||||
* Code is now in strict mode
|
|
||||||
* Cleaned up a few messy areas
|
|
||||||
|
|
||||||
### Version 1.6 ###
|
|
||||||
If the 1.6 release has a theme, it is flexibility. Nearly every update in this release is intended to allow greater flexibility for developers.
|
|
||||||
|
|
||||||
* Submitting a file which exceeds `maxSize` or is not an `allowedExtension` no longer triggers an alert, but will instead fire a callback
|
|
||||||
* Added `onSizeError()` callback function which fires when a file exceeds the `maxSize` option, if it is set
|
|
||||||
* Added `onExtError()` callback which fires when a file is not permitted by the `allowedExtensions` option, if it is set
|
|
||||||
* Removed `messages` option and `_errorMsg()`, both of which are no longer used
|
|
||||||
* Added new `accept` option, the value of which will be the value of the `accept` file input attribute in supporting browsers. <a href="http://stackoverflow.com/a/10503561/1091949">More info.</a>
|
|
||||||
* Added new `method` option to allow specifying an HTTP method other than POST
|
|
||||||
|
|
||||||
Special thanks to <a href="https://github.com/dleffler">dleffler</a>, <a href="https://github.com/devtrends">devtrends</a> and <a href="https://github.com/urcadox">urcadox</a> for their ideas and feedback.
|
|
||||||
|
|
||||||
### Version 1.5.3 ###
|
|
||||||
* Added `autoSubmit` check before submitting in `_cycleQueue()`
|
|
||||||
* Added check to ensure upload progress server key doesn't exceed 57 characters (max allowable APC key length)
|
|
||||||
* `rerouteClicks(element)` can now be used to add additional elements which can be clicked to open file box
|
|
||||||
|
|
||||||
### Version 1.5.2 ###
|
|
||||||
(This isn't as much a release as it is a signal to update for anyone who may have downloaded version 1.5.1 in the past few hours)
|
|
||||||
* Fixed "bug" from 1.5.1 that broke uploader without multiple option enabled
|
|
||||||
* Added `queue` option to disable automatic file queuing
|
|
||||||
|
|
||||||
### Version 1.5.1 ###
|
|
||||||
* Multiple file inputs are now used in browsers with support for File API, thus allowing multiple file selection if `multiple` option is `true`
|
|
||||||
* Removed some unnecessary variable copying
|
|
||||||
* Added queue system which allows files to be selected and automatically uploaded as others finish
|
|
||||||
* Added `getQueueSize()` function to get current number of files waiting in queue
|
|
||||||
* Fixed bug in which active upload counter was not properly updating when returning `false` from `startXHR()` and `startNonXHR()`
|
|
||||||
* Error messages now incorporate file names
|
|
||||||
|
|
||||||
### Version 1.5 ###
|
|
||||||
* Added support for multiple file uploading, along with Gmail-style multiple progress bars for tracking each file.
|
|
||||||
* Added new `maxSize` option for file size limits, `allowedExtensions` option for file type restrictions. Custom error messages supported for both.
|
|
||||||
* Updated `verifyElem()` to use a better method of detecting if an upload button is a jQuery object.
|
|
||||||
* Numerous code enhancements throughout - updated error handling, cleaner organization, performance improvements.
|
|
||||||
* Patched some memory leaks created by circular references in event handlers.
|
|
||||||
|
|
||||||
### Version 1.4.2 ###
|
|
||||||
* SimpleAjaxUploader.js - Added `multipart` option to allow multipart form upload instead of binary stream
|
|
||||||
* Uploader.php - The check for form uploads is now first in the constructor to accomodate new `multipart` option
|
|
||||||
* Uploader.php - Providing an array of valid file extensions is now optional. If not provided, all file types are allowed
|
|
||||||
* Added minified version of JS file
|
|
||||||
|
|
||||||
### Version 1.4.1 ###
|
|
||||||
* Fixed XHR status check logic that could allow false alarm calls to onError callback
|
|
||||||
* Removed redundant XHR status check
|
|
||||||
* Returning false from a callback no longer clears the file field. Not sure why it ever did to begin with.
|
|
||||||
* A status check now occurs prior to progress update requests to prevent potential loop that could be caused by a server error
|
|
||||||
* Parsing JSON in older browsers no longer uses `eval` because it's evil
|
|
||||||
|
|
||||||
### Version 1.4 ###
|
|
||||||
This release includes a major overhaul that adds functionality for implementing cross-browser upload progress support. Through feature detection and abstraction, it is now possible for the `onProgress` callback function to maintain consistent behavior across browsers.
|
|
||||||
|
|
||||||
Currently, only PHP (with APC extension) is supported. To use, set the newly added `progressUrl` option to the URL of the included UploadProgress.php script, and `onProgress` will then return upload progress data in Internet Explorer 9 and below.
|
|
||||||
|
|
||||||
Note that this added functionality does not affect the behavior of the plugin for those not using PHP, or just not using the feature.
|
|
||||||
|
|
||||||
For those not using PHP, a similar result can still be achieved with the `startXH`/`endXHR` and `startNonXHR`/`endNonXHR` callback functions, which are included specifically for defining behavior based on whether XHR uploads are supported.
|
|
||||||
|
|
||||||
Also, adding support for other programming languages would certainly be a welcome addition, if anyone is interested in working on that.
|
|
||||||
|
|
||||||
Other items:
|
|
||||||
|
|
||||||
* Added `onUpdateFileSize` callback function for getting file size in IE9 and below (When server supported progress is enabled)
|
|
||||||
* Removed the unneccessary _handleJSON method
|
|
||||||
* Added new ss.newXHR method
|
|
||||||
* Added extras folder for non-necessary items (i.e., everything but SimpleAjaxUploader.js)
|
|
||||||
* Adjusted request headers for XHR uploads
|
|
||||||
* Moved support detection for HTML5 File API to constructor so it only executes once
|
|
||||||
* Timestamps now appended to URLs to prevent browsers from caching requests
|
|
||||||
|
|
||||||
### Version 1.3 ###
|
|
||||||
* Returned to version numbering
|
|
||||||
* Updated method for parsing JSON
|
|
||||||
* Added PHP class for handling file uploads
|
|
||||||
* Cleaned up messy areas
|
|
||||||
|
|
||||||
### Earlier versions ###
|
|
||||||
Prior to version 1.3, I did a pretty horrible job of documenting changes, and, at one point, entirely dispensed with any notion of version control whatsoever. I have since seen the light.
|
|
||||||
@@ -1,258 +0,0 @@
|
|||||||
Simple Ajax Uploader
|
|
||||||
============================
|
|
||||||
|
|
||||||
A Javascript plugin for cross-browser Ajax file uploading. Supports drag and drop, CORS, and multiple file uploading with progress bars. Works in IE7-9, mobile, and all modern browsers.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var uploader = new ss.SimpleUpload({
|
|
||||||
button: 'upload-btn', // HTML element used as upload button
|
|
||||||
url: '/PathTo/UploadHandler', // URL of server-side upload handler
|
|
||||||
name: 'uploadfile' // Parameter name of the uploaded file
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
### Features ###
|
|
||||||
* Cross-browser -- works in IE7+, Firefox, Chrome, Safari, Opera
|
|
||||||
* Supports multiple, concurrent file uploads (even in non-HTML5 browsers)
|
|
||||||
* Built-in CORS support
|
|
||||||
* Drag and drop file uploads (<strong>new in v2.0</strong>)
|
|
||||||
* No flash or external CSS -- a single 6Kb Javascript file (minified and gzipped)
|
|
||||||
* Progress bars in all browsers, including IE9 and older. Built-in support for:
|
|
||||||
* <a href="http://wiki.nginx.org/HttpUploadProgressModule">Nginx Upload Progress Module</a>
|
|
||||||
* <a href="http://www.php.net/manual/en/apc.configuration.php#ini.apc.rfc1867">PHP APC File Upload Progress</a>
|
|
||||||
* <a href="http://php.net/manual/en/session.upload-progress.php">PHP Session Upload Progress</a>
|
|
||||||
* Use any HTML element as the upload button
|
|
||||||
* No dependencies - use it with or without jQuery
|
|
||||||
* Provides individual callback functions for XHR-supported browsers and for browsers that do not support XHR uploads
|
|
||||||
* Ability to pass custom headers in request such as the Authorization header
|
|
||||||
|
|
||||||
### How to Use ###
|
|
||||||
|
|
||||||
<a href="https://www.lpology.com/code/ajaxuploader/">Live Demo</a><br />
|
|
||||||
<a href="https://www.lpology.com/code/ajaxuploader/docs.php">API Reference</a><br />
|
|
||||||
<a href="https://www.lpology.com/code/ajaxuploader/progress.php">Upload progress bars in IE9 (and older)</a><br />
|
|
||||||
<a href="https://www.lpology.com/code/ajaxuploader/How-to-Cross-Domain-File-Uploading.php">CORS — Cross-domain file uploading with Simple Ajax Uploader</a>
|
|
||||||
|
|
||||||
There are two main ways to use the plugin:
|
|
||||||
|
|
||||||
<strong>1. Single file uploading</strong> - Only one upload allowed at a time. Progress bar is an element that is re-used for each upload.<br />
|
|
||||||
<strong>2. Multiple file uploading</strong> - Allow multiple, concurrent file uploads. Progress bars are created on the fly before each upload.
|
|
||||||
|
|
||||||
#### Method 1: Single file uploading (one file at a time) ####
|
|
||||||
|
|
||||||
Before each upload, in the `onSubmit()` callback function, the on-page <code>sizeBox</code> and <code>progress</code> elements are assigned specific roles using these two functions:
|
|
||||||
|
|
||||||
`setProgressBar(elem)` - Designates an element as the progress bar for an upload.<br />
|
|
||||||
`setFileSizeBox(elem)` - Designates an element as the container in which the file size of an uploading file will be inserted.
|
|
||||||
|
|
||||||
As a result, when an upload begins, the file size of the upload is inserted into the <code>sizeBox</code> element and the CSS width of the <code>progress</code> element is set to 0%. As the upload progresses, the CSS width percentage of the <code>progress</code> element will be updated accordingly.
|
|
||||||
|
|
||||||
This approach of assigning roles to elements provides developers with a great deal of flexibility -- progress indicators can be styled in any way and placed anywhere on the page.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var sizeBox = document.getElementById('sizeBox'), // container for file size info
|
|
||||||
progress = document.getElementById('progress'); // the element we're using for a progress bar
|
|
||||||
|
|
||||||
var uploader = new ss.SimpleUpload({
|
|
||||||
button: 'uploadButton', // file upload button
|
|
||||||
url: 'uploadHandler.php', // server side handler
|
|
||||||
name: 'uploadfile', // upload parameter name
|
|
||||||
progressUrl: 'uploadProgress.php', // enables cross-browser progress support (more info below)
|
|
||||||
responseType: 'json',
|
|
||||||
allowedExtensions: ['jpg', 'jpeg', 'png', 'gif'],
|
|
||||||
maxSize: 1024, // kilobytes
|
|
||||||
hoverClass: 'ui-state-hover',
|
|
||||||
focusClass: 'ui-state-focus',
|
|
||||||
disabledClass: 'ui-state-disabled',
|
|
||||||
onSubmit: function(filename, extension) {
|
|
||||||
this.setFileSizeBox(sizeBox); // designate this element as file size container
|
|
||||||
this.setProgressBar(progress); // designate as progress bar
|
|
||||||
},
|
|
||||||
onComplete: function(filename, response) {
|
|
||||||
if (!response) {
|
|
||||||
alert(filename + 'upload failed');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// do something with response...
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Method 2: Multiple file uploads ####
|
|
||||||
|
|
||||||
Below is an example of how to implement multiple file uploading with progress bars. A new progress bar is created for each file upload within the `onSubmit()` callback function.
|
|
||||||
|
|
||||||
Like in Method 1, the newly created elements are assigned roles using the `setProgressBar()` and `setFileSizeBox()` functions. Unlike the previous example, however, the progress elements are automatically removed when the upload is completed.
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var uploader = new ss.SimpleUpload({
|
|
||||||
button: 'uploadButton',
|
|
||||||
url: 'uploadHandler.php', // server side handler
|
|
||||||
progressUrl: 'uploadProgress.php', // enables cross-browser progress support (more info below)
|
|
||||||
responseType: 'json',
|
|
||||||
name: 'uploadfile',
|
|
||||||
multiple: true,
|
|
||||||
allowedExtensions: ['jpg', 'jpeg', 'png', 'gif'], // for example, if we were uploading pics
|
|
||||||
hoverClass: 'ui-state-hover',
|
|
||||||
focusClass: 'ui-state-focus',
|
|
||||||
disabledClass: 'ui-state-disabled',
|
|
||||||
onSubmit: function(filename, extension) {
|
|
||||||
// Create the elements of our progress bar
|
|
||||||
var progress = document.createElement('div'), // container for progress bar
|
|
||||||
bar = document.createElement('div'), // actual progress bar
|
|
||||||
fileSize = document.createElement('div'), // container for upload file size
|
|
||||||
wrapper = document.createElement('div'), // container for this progress bar
|
|
||||||
progressBox = document.getElementById('progressBox'); // on page container for progress bars
|
|
||||||
|
|
||||||
// Assign each element its corresponding class
|
|
||||||
progress.className = 'progress';
|
|
||||||
bar.className = 'bar';
|
|
||||||
fileSize.className = 'size';
|
|
||||||
wrapper.className = 'wrapper';
|
|
||||||
|
|
||||||
// Assemble the progress bar and add it to the page
|
|
||||||
progress.appendChild(bar);
|
|
||||||
wrapper.innerHTML = '<div class="name">'+filename+'</div>'; // filename is passed to onSubmit()
|
|
||||||
wrapper.appendChild(fileSize);
|
|
||||||
wrapper.appendChild(progress);
|
|
||||||
progressBox.appendChild(wrapper); // just an element on the page to hold the progress bars
|
|
||||||
|
|
||||||
// Assign roles to the elements of the progress bar
|
|
||||||
this.setProgressBar(bar); // will serve as the actual progress bar
|
|
||||||
this.setFileSizeBox(fileSize); // display file size beside progress bar
|
|
||||||
this.setProgressContainer(wrapper); // designate the containing div to be removed after upload
|
|
||||||
},
|
|
||||||
|
|
||||||
// Do something after finishing the upload
|
|
||||||
// Note that the progress bar will be automatically removed upon completion because everything
|
|
||||||
// is encased in the "wrapper", which was designated to be removed with setProgressContainer()
|
|
||||||
onComplete: function(filename, response) {
|
|
||||||
if (!response) {
|
|
||||||
alert(filename + 'upload failed');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Stuff to do after finishing an upload...
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
For multiple file uploads, we use an additional function: `setProgressContainer(elem)`. This function designates an element to be removed from the DOM after the upload is completed.
|
|
||||||
|
|
||||||
In the example, the element set to be removed with `setProgressContainer()` is the outer container for the progress elements. As a result, progress bars will be removed from the DOM after each upload is completed.
|
|
||||||
|
|
||||||
### Cross-Browser Helper Functions ###
|
|
||||||
|
|
||||||
To ease the pain of supporting older browsers, the plugin includes a set of callback functions which allow specific behavior to be defined based on whether the user's browser supports XHR uploads/HTML5 File API:
|
|
||||||
|
|
||||||
<code>startXHR(filename, fileSize)</code> - Called prior to upload -- only in browsers that support XHR uploads<br />
|
|
||||||
<code>endXHR(filename)</code> - Called after upload is completed -- only in browsers that support XHR uploads<br />
|
|
||||||
<code>startNonXHR(filename)</code> - Called prior to upload -- only in browsers that <strong>do not</strong> support XHR uploads<br />
|
|
||||||
<code>endNonXHR(filename)</code> - Called after upload is completed -- only in browsers that <strong>do not</strong> support XHR uploads<br />
|
|
||||||
|
|
||||||
A common use case is to show an upload progress bar in browsers that support the <code>progress</code> event while displaying an animated GIF in older browsers:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
|
|
||||||
var progress = document.getElementById('progress'), // progress bar
|
|
||||||
loaderImg = document.getElementById('loaderImg'); // "loading" animated GIF
|
|
||||||
|
|
||||||
var uploader = new ss.SimpleUpload({
|
|
||||||
button: 'uploadButton',
|
|
||||||
url: 'uploadHandler.php', // server side handler
|
|
||||||
responseType: 'json',
|
|
||||||
name: 'uploadfile',
|
|
||||||
hoverClass: 'ui-state-hover',
|
|
||||||
focusClass: 'ui-state-focus',
|
|
||||||
disabledClass: 'ui-state-disabled',
|
|
||||||
startXHR: function(filename, size) {
|
|
||||||
progress.style.display = 'inline-block'; // show progress bar
|
|
||||||
this.setProgressBar(progress); // designate as progress bar
|
|
||||||
},
|
|
||||||
endXHR: function(filename) {
|
|
||||||
progress.style.display = 'none'; // hide progress bar
|
|
||||||
},
|
|
||||||
startNonXHR: function(filename) {
|
|
||||||
loaderImg.style.display = 'inline-block'; // show animated GIF
|
|
||||||
},
|
|
||||||
endNonXHR: function(filename) {
|
|
||||||
loaderImg.style.display = 'none'; // hide animated GIF
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
Returning <code>false</code> from <code>startXHR()</code> and <code>startNonXHR()</code> will prevent the upload from starting, just as it does with <code>onSubmit()</code> and <code>onChange()</code>.
|
|
||||||
|
|
||||||
### Server-side file handling ###
|
|
||||||
Files are uploaded by POST as either raw form data or regular multipart/form-data, depending on the browser.
|
|
||||||
|
|
||||||
### Using Uploader.php ###
|
|
||||||
|
|
||||||
<strong>Note:</strong> This PHP class is included only for convenience. <strong>It is not required to use PHP with Simple Ajax Uploader.</strong> The plugin is agnostic to server configuration, so use any language you prefer.
|
|
||||||
|
|
||||||
```php
|
|
||||||
<?php
|
|
||||||
require('Uploader.php');
|
|
||||||
|
|
||||||
$upload_dir = '/img_uploads/';
|
|
||||||
$valid_extensions = array('gif', 'png', 'jpeg', 'jpg');
|
|
||||||
|
|
||||||
$Upload = new FileUpload('uploadfile');
|
|
||||||
$result = $Upload->handleUpload($upload_dir, $valid_extensions);
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
echo json_encode(array('success' => false, 'msg' => $Upload->getErrorMsg()));
|
|
||||||
} else {
|
|
||||||
echo json_encode(array('success' => true, 'file' => $Upload->getFileName()));
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
You can also save the uploaded file with a different name by setting the `newFileName` property:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$Upload = new FileUpload('uploadfile');
|
|
||||||
$ext = $Upload->getExtension(); // Get the extension of the uploaded file
|
|
||||||
$Upload->newFileName = 'customFileName.'.$ext;
|
|
||||||
$result = $Upload->handleUpload($upload_dir, $valid_extensions);
|
|
||||||
```
|
|
||||||
|
|
||||||
To access the newly uploaded file, use the `getSavedFile()` method to get the file's path after the upload is completed:
|
|
||||||
```php
|
|
||||||
$Upload = new FileUpload('uploadfile');
|
|
||||||
$result = $Upload->handleUpload($upload_dir, $valid_extensions);
|
|
||||||
|
|
||||||
if ($result) {
|
|
||||||
$path = $Upload->getSavedFile();
|
|
||||||
$imgsize = getimagesize($path);
|
|
||||||
// image resizing stuff...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Passing Custom Headers ###
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var uploader = new ss.SimpleUpload({
|
|
||||||
customHeaders: {'Authorization': 'my-access-token'},
|
|
||||||
...
|
|
||||||
});
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
### Drag and Drop ###
|
|
||||||
|
|
||||||
Enable drag and drop uploading by passing an element to the `dropzone` option to serve as the drop zone:
|
|
||||||
|
|
||||||
```javascript
|
|
||||||
var uploader = new ss.SimpleUpload({
|
|
||||||
dropzone: 'dragbox', // ID of element to be the drop zone
|
|
||||||
url: 'uploadHandler.php',
|
|
||||||
name: 'uploadfile',
|
|
||||||
responseType: 'json',
|
|
||||||
onComplete: function(filename, response) {
|
|
||||||
// do something with response...
|
|
||||||
}
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### License ###
|
|
||||||
Released under the MIT license.
|
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@@ -1,254 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple Ajax Uploader
|
|
||||||
* Version 2.0
|
|
||||||
* https://github.com/LPology/Simple-Ajax-Uploader
|
|
||||||
*
|
|
||||||
* Copyright 2012-2015 LPology, LLC
|
|
||||||
* Released under the MIT license
|
|
||||||
*
|
|
||||||
* View the documentation for an example of how to use this class.
|
|
||||||
*/
|
|
||||||
|
|
||||||
class FileUpload {
|
|
||||||
private $fileName; // Filename of the uploaded file
|
|
||||||
private $fileSize; // Size of uploaded file in bytes
|
|
||||||
private $fileExtension; // File extension of uploaded file
|
|
||||||
private $fileNameWithoutExt;
|
|
||||||
private $savedFile; // Path to newly uploaded file (after upload completed)
|
|
||||||
private $errorMsg; // Error message if handleUpload() returns false (use getErrorMsg() to retrieve)
|
|
||||||
private $isXhr;
|
|
||||||
public $uploadDir; // File upload directory (include trailing slash)
|
|
||||||
public $allowedExtensions; // Array of permitted file extensions
|
|
||||||
public $sizeLimit = 10485760; // Max file upload size in bytes (default 10MB)
|
|
||||||
public $newFileName; // Optionally save uploaded files with a new name by setting this
|
|
||||||
public $corsInputName = 'XHR_CORS_TARGETORIGIN';
|
|
||||||
public $uploadName = 'uploadfile';
|
|
||||||
|
|
||||||
function __construct($uploadName = null) {
|
|
||||||
if ($uploadName !== null) {
|
|
||||||
$this->uploadName = $uploadName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_FILES[$this->uploadName])) {
|
|
||||||
$this->isXhr = false;
|
|
||||||
|
|
||||||
if ($_FILES[$this->uploadName]['error'] === UPLOAD_ERR_OK) {
|
|
||||||
$this->fileName = $_FILES[$this->uploadName]['name'];
|
|
||||||
$this->fileSize = $_FILES[$this->uploadName]['size'];
|
|
||||||
|
|
||||||
} else {
|
|
||||||
$this->setErrorMsg($this->errorCodeToMsg($_FILES[$this->uploadName]['error']));
|
|
||||||
}
|
|
||||||
|
|
||||||
} elseif (isset($_SERVER['HTTP_X_FILE_NAME']) || isset($_GET[$this->uploadName])) {
|
|
||||||
$this->isXhr = true;
|
|
||||||
|
|
||||||
$this->fileName = isset($_SERVER['HTTP_X_FILE_NAME']) ?
|
|
||||||
$_SERVER['HTTP_X_FILE_NAME'] : $_GET[$this->uploadName];
|
|
||||||
|
|
||||||
if (isset($_SERVER['CONTENT_LENGTH'])) {
|
|
||||||
$this->fileSize = (int)$_SERVER['CONTENT_LENGTH'];
|
|
||||||
|
|
||||||
} else {
|
|
||||||
throw new Exception('Content length is empty.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->fileName) {
|
|
||||||
$pathinfo = pathinfo($this->fileName);
|
|
||||||
|
|
||||||
if (array_key_exists('extension', $pathinfo) &&
|
|
||||||
array_key_exists('filename', $pathinfo))
|
|
||||||
{
|
|
||||||
$this->fileExtension = strtolower($pathinfo['extension']);
|
|
||||||
$this->fileNameWithoutExt = $pathinfo['filename'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFileName() {
|
|
||||||
return $this->fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFileSize() {
|
|
||||||
return $this->fileSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getExtension() {
|
|
||||||
return $this->fileExtension;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getErrorMsg() {
|
|
||||||
return $this->errorMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSavedFile() {
|
|
||||||
return $this->savedFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function errorCodeToMsg($code) {
|
|
||||||
switch($code) {
|
|
||||||
case UPLOAD_ERR_INI_SIZE:
|
|
||||||
$message = 'File size exceeds limit.';
|
|
||||||
break;
|
|
||||||
case UPLOAD_ERR_PARTIAL:
|
|
||||||
$message = 'The uploaded file was only partially uploaded.';
|
|
||||||
break;
|
|
||||||
case UPLOAD_ERR_NO_FILE:
|
|
||||||
$message = 'No file was uploaded.';
|
|
||||||
break;
|
|
||||||
case UPLOAD_ERR_NO_TMP_DIR:
|
|
||||||
$message = 'Missing a temporary folder.';
|
|
||||||
break;
|
|
||||||
case UPLOAD_ERR_CANT_WRITE:
|
|
||||||
$message = 'Failed to write file to disk.';
|
|
||||||
break;
|
|
||||||
case UPLOAD_ERR_EXTENSION:
|
|
||||||
$message = 'File upload stopped by extension.';
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
$message = 'Unknown upload error.';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return $message;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function checkExtension($ext, $allowedExtensions) {
|
|
||||||
if (!is_array($allowedExtensions))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!in_array(strtolower($ext), array_map('strtolower', $allowedExtensions)))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function setErrorMsg($msg) {
|
|
||||||
if (empty($this->errorMsg))
|
|
||||||
$this->errorMsg = $msg;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function fixDir($dir) {
|
|
||||||
if (empty($dir))
|
|
||||||
return $dir;
|
|
||||||
|
|
||||||
$slash = DIRECTORY_SEPARATOR;
|
|
||||||
$dir = str_replace('/', $slash, $dir);
|
|
||||||
$dir = str_replace('\\', $slash, $dir);
|
|
||||||
return substr($dir, -1) == $slash ? $dir : $dir . $slash;
|
|
||||||
}
|
|
||||||
|
|
||||||
// escapeJS and jsMatcher are adapted from the Escaper component of
|
|
||||||
// Zend Framework, Copyright (c) 2005-2013, Zend Technologies USA, Inc.
|
|
||||||
// https://github.com/zendframework/zf2/tree/master/library/Zend/Escaper
|
|
||||||
private function escapeJS($string) {
|
|
||||||
return preg_replace_callback('/[^a-z0-9,\._]/iSu', $this->jsMatcher, $string);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function jsMatcher($matches) {
|
|
||||||
$chr = $matches[0];
|
|
||||||
|
|
||||||
if (strlen($chr) == 1)
|
|
||||||
return sprintf('\\x%02X', ord($chr));
|
|
||||||
|
|
||||||
if (function_exists('iconv'))
|
|
||||||
$chr = iconv('UTF-16BE', 'UTF-8', $chr);
|
|
||||||
|
|
||||||
elseif (function_exists('mb_convert_encoding'))
|
|
||||||
$chr = mb_convert_encoding($chr, 'UTF-8', 'UTF-16BE');
|
|
||||||
|
|
||||||
return sprintf('\\u%04s', strtoupper(bin2hex($chr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function corsResponse($data) {
|
|
||||||
if (isset($_REQUEST[$this->corsInputName])) {
|
|
||||||
$targetOrigin = $this->escapeJS($_REQUEST[$this->corsInputName]);
|
|
||||||
$targetOrigin = htmlspecialchars($targetOrigin, ENT_QUOTES, 'UTF-8');
|
|
||||||
return "<script>window.parent.postMessage('$data','$targetOrigin');</script>";
|
|
||||||
}
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function saveXhr($path) {
|
|
||||||
if (false !== file_put_contents($path, fopen('php://input', 'r')))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function saveForm($path) {
|
|
||||||
if (move_uploaded_file($_FILES[$this->uploadName]['tmp_name'], $path))
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function save($path) {
|
|
||||||
if (true === $this->isXhr)
|
|
||||||
return $this->saveXhr($path);
|
|
||||||
return $this->saveForm($path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function handleUpload($uploadDir = null, $allowedExtensions = null) {
|
|
||||||
if (!$this->fileName) {
|
|
||||||
$this->setErrorMsg('Incorrect upload name or no file uploaded');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->fileSize == 0) {
|
|
||||||
$this->setErrorMsg('File is empty');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->fileSize > $this->sizeLimit) {
|
|
||||||
$this->setErrorMsg('File size exceeds limit');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!empty($uploadDir))
|
|
||||||
$this->uploadDir = $uploadDir;
|
|
||||||
|
|
||||||
$this->uploadDir = $this->fixDir($this->uploadDir);
|
|
||||||
|
|
||||||
if (!is_writable($this->uploadDir)) {
|
|
||||||
$this->setErrorMsg('Upload directory is not writable');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_array($allowedExtensions))
|
|
||||||
$this->allowedExtensions = $allowedExtensions;
|
|
||||||
|
|
||||||
if (!empty($this->allowedExtensions)) {
|
|
||||||
if (!$this->checkExtension($this->fileExtension, $this->allowedExtensions)) {
|
|
||||||
$this->setErrorMsg('Invalid file type');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->savedFile = $this->uploadDir . $this->fileName;
|
|
||||||
|
|
||||||
if (!empty($this->newFileName)) {
|
|
||||||
$this->fileName = $this->newFileName;
|
|
||||||
$this->savedFile = $this->uploadDir . $this->fileName;
|
|
||||||
|
|
||||||
$this->fileNameWithoutExt = null;
|
|
||||||
$this->fileExtension = null;
|
|
||||||
|
|
||||||
$pathinfo = pathinfo($this->fileName);
|
|
||||||
|
|
||||||
if (array_key_exists('filename', $pathinfo))
|
|
||||||
$this->fileNameWithoutExt = $pathinfo['filename'];
|
|
||||||
|
|
||||||
if (array_key_exists('extension', $pathinfo))
|
|
||||||
$this->fileExtension = strtolower($pathinfo['extension']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->save($this->savedFile)) {
|
|
||||||
$this->setErrorMsg('File could not be saved');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
725
etc/apps/laragon/extras/assets/css/bootstrap.min.css
vendored
725
etc/apps/laragon/extras/assets/css/bootstrap.min.css
vendored
File diff suppressed because one or more lines are too long
@@ -1,28 +0,0 @@
|
|||||||
.container {
|
|
||||||
width: auto;
|
|
||||||
max-width: 680px;
|
|
||||||
padding: 0 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.progress {
|
|
||||||
margin-bottom:0;
|
|
||||||
margin-top:6px;
|
|
||||||
margin-left:10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.focus {
|
|
||||||
outline:thin dotted #333;
|
|
||||||
outline:5px auto -webkit-focus-ring-color;
|
|
||||||
outline-offset:-2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn.hover {
|
|
||||||
color:#ffffff;
|
|
||||||
background-color:#3276b1;
|
|
||||||
border-color:#285e8e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.highlight {
|
|
||||||
background-color: yellow;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple Ajax Uploader
|
|
||||||
* Version 2.0
|
|
||||||
* https://github.com/LPology/Simple-Ajax-Uploader
|
|
||||||
*
|
|
||||||
* Copyright 2012-2015 LPology, LLC
|
|
||||||
* Released under the MIT license
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (isset($_SERVER['HTTP_ORIGIN'])) {
|
|
||||||
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
|
|
||||||
header('Access-Control-Allow-Credentials: true');
|
|
||||||
header('Access-Control-Max-Age: 86400'); // cache for 1 day
|
|
||||||
}
|
|
||||||
|
|
||||||
// Access-Control headers are received during OPTIONS requests
|
|
||||||
if (isset($_SERVER['REQUEST_METHOD'])) {
|
|
||||||
|
|
||||||
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
|
|
||||||
|
|
||||||
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) {
|
|
||||||
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) {
|
|
||||||
header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}");
|
|
||||||
}
|
|
||||||
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
require('Uploader.php');
|
|
||||||
|
|
||||||
// Directory where we're storing uploaded images
|
|
||||||
// Remember to set correct permissions or it won't work
|
|
||||||
$upload_dir = '../uploads';
|
|
||||||
|
|
||||||
$uploader = new FileUpload('uploadfile');
|
|
||||||
$uploader->sizeLimit = 1024*1024*1024; // Max file upload size in bytes 1GB)
|
|
||||||
|
|
||||||
// Handle the upload
|
|
||||||
$result = $uploader->handleUpload($upload_dir);
|
|
||||||
|
|
||||||
if (!$result) {
|
|
||||||
exit(json_encode(array('success' => false, 'msg' => $uploader->getErrorMsg())));
|
|
||||||
}
|
|
||||||
|
|
||||||
echo json_encode(array('success' => true));
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple Ajax Uploader
|
|
||||||
* Version 2.0
|
|
||||||
* https://github.com/LPology/Simple-Ajax-Uploader
|
|
||||||
*
|
|
||||||
* Copyright 2012-2015 LPology, LLC
|
|
||||||
* Released under the MIT license
|
|
||||||
*
|
|
||||||
* Returns upload progress updates for browsers that don't support the HTML5 File API.
|
|
||||||
* Falling back to this method allows for upload progress support across virtually all browsers.
|
|
||||||
* Requires PHP 5.4+
|
|
||||||
* Further documentation: http://php.net/manual/en/session.upload-progress.php
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
session_start();
|
|
||||||
|
|
||||||
if (!isset($_POST[ini_get('session.upload_progress.name')])) {
|
|
||||||
exit(json_encode(array('success' => false)));
|
|
||||||
}
|
|
||||||
|
|
||||||
$key = ini_get('session.upload_progress.prefix') . $_POST[ini_get('session.upload_progress.name')];
|
|
||||||
|
|
||||||
if (!isset($_SESSION[$key])) {
|
|
||||||
exit(json_encode(array('success' => false)));
|
|
||||||
}
|
|
||||||
|
|
||||||
$progress = $_SESSION[$key];
|
|
||||||
$pct = 0;
|
|
||||||
$size = 0;
|
|
||||||
|
|
||||||
if (is_array($progress)) {
|
|
||||||
|
|
||||||
if (array_key_exists('bytes_processed', $progress) && array_key_exists('content_length', $progress)) {
|
|
||||||
|
|
||||||
if ($progress['content_length'] > 0) {
|
|
||||||
$pct = round(($progress['bytes_processed'] / $progress['content_length']) * 100);
|
|
||||||
$size = round($progress['content_length'] / 1024);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo json_encode(array('success' => true, 'pct' => $pct, 'size' => $size));
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple Ajax Uploader
|
|
||||||
* Version 2.0
|
|
||||||
* https://github.com/LPology/Simple-Ajax-Uploader
|
|
||||||
*
|
|
||||||
* Copyright 2012-2015 LPology, LLC
|
|
||||||
* Released under the MIT license
|
|
||||||
*
|
|
||||||
* Returns upload progress updates for browsers that don't support the HTML5 File API.
|
|
||||||
* Falling back to this method allows for upload progress support across virtually all browsers.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
// This "if" statement is only necessary for CORS uploads -- if you're
|
|
||||||
// only doing same-domain uploads then you can delete it if you want
|
|
||||||
if (isset($_SERVER['HTTP_ORIGIN'])) {
|
|
||||||
header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}");
|
|
||||||
header('Access-Control-Allow-Credentials: true');
|
|
||||||
header('Access-Control-Max-Age: 86400'); // cache for 1 day
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset($_REQUEST['progresskey'])) {
|
|
||||||
$status = apc_fetch('upload_'.$_REQUEST['progresskey']);
|
|
||||||
} else {
|
|
||||||
exit(json_encode(array('success' => false)));
|
|
||||||
}
|
|
||||||
|
|
||||||
$pct = 0;
|
|
||||||
$size = 0;
|
|
||||||
|
|
||||||
if (is_array($status)) {
|
|
||||||
|
|
||||||
if (array_key_exists('total', $status) && array_key_exists('current', $status)) {
|
|
||||||
|
|
||||||
if ($status['total'] > 0) {
|
|
||||||
$pct = round(($status['current'] / $status['total']) * 100);
|
|
||||||
$size = round($status['total'] / 1024);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo json_encode(array('success' => true, 'pct' => $pct, 'size' => $size));
|
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
<?php
|
|
||||||
function formatLink($file) {
|
|
||||||
if (isset($_SERVER['HTTPS']) &&
|
|
||||||
($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
|
|
||||||
isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
|
|
||||||
$_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
|
|
||||||
$protocol = 'https';
|
|
||||||
} else {
|
|
||||||
$protocol = 'http';
|
|
||||||
}
|
|
||||||
$link = sprintf('%s://%s/laragon/uploads/%s', $protocol, $_SERVER['HTTP_HOST'], $file);
|
|
||||||
return sprintf('<a href="%s" target="_blank">%s</a>', $link, $link);
|
|
||||||
}
|
|
||||||
function listFiles() {
|
|
||||||
$upload_dir = dirname(__FILE__).'\uploads';
|
|
||||||
echo sprintf('<div>Files locate at: <b>%s</b></div>', $upload_dir);
|
|
||||||
if ($handle = opendir($upload_dir)) {
|
|
||||||
|
|
||||||
while (false !== ($entry = readdir($handle))) {
|
|
||||||
if ($entry != "." && $entry != "..") {
|
|
||||||
echo '<div>'.formatLink($entry).'</div>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
closedir($handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
?>
|
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Uploader</title>
|
|
||||||
<link href="extras/assets/css/bootstrap.min.css" rel="stylesheet">
|
|
||||||
<link href="extras/assets/css/styles.css" rel="stylesheet">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<div class="row" style="padding-top:10px;">
|
|
||||||
<div class="col-xs-2">
|
|
||||||
<button id="uploadBtn" class="btn btn-large btn-primary">Choose Files</button>
|
|
||||||
</div>
|
|
||||||
<div class="col-xs-10">
|
|
||||||
<div id="progressOuter" class="progress progress-striped active" style="display:none;">
|
|
||||||
<div id="progressBar" class="progress-bar progress-bar-success" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 0%">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row" style="padding-top:10px;">
|
|
||||||
<div class="col-xs-10">
|
|
||||||
<div id="msgBox">
|
|
||||||
</div>
|
|
||||||
<div id="uploadedFiles">
|
|
||||||
</div>
|
|
||||||
<p>
|
|
||||||
<hr />
|
|
||||||
<div>
|
|
||||||
<small>
|
|
||||||
<div><u>Tip</u>: Hold Shift if you want to upload multiple files.</div>
|
|
||||||
<div>If you want to share over the Internet, just run:</div>
|
|
||||||
<div><b><i>ngrok http 80</i></b></div>
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
<hr />
|
|
||||||
<div id="listFiles">
|
|
||||||
<?php
|
|
||||||
listFiles();
|
|
||||||
|
|
||||||
//$upload_dir = dirname(__FILE__).'\uploads';
|
|
||||||
//echo $upload_dir;
|
|
||||||
//echo '<a href="http://'.$_SERVER['HTTP_HOST'].'/laragon/uploads/" target="_blank">'.$_SERVER['HTTP_HOST'].'</a>';
|
|
||||||
?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script src="extras/SimpleAjaxUploader.min.js"></script>
|
|
||||||
<script>
|
|
||||||
function escapeTags( str ) {
|
|
||||||
return String( str )
|
|
||||||
.replace( /&/g, '&' )
|
|
||||||
.replace( /"/g, '"' )
|
|
||||||
.replace( /'/g, ''' )
|
|
||||||
.replace( /</g, '<' )
|
|
||||||
.replace( />/g, '>' );
|
|
||||||
}
|
|
||||||
|
|
||||||
function replaceAll(str, find, replace) {
|
|
||||||
return str.replace(new RegExp(find, 'g'), replace);
|
|
||||||
}
|
|
||||||
|
|
||||||
window.onload = function() {
|
|
||||||
|
|
||||||
var btn = document.getElementById('uploadBtn'),
|
|
||||||
progressBar = document.getElementById('progressBar'),
|
|
||||||
progressOuter = document.getElementById('progressOuter'),
|
|
||||||
msgBox = document.getElementById('msgBox');
|
|
||||||
listFiles = document.getElementById('listFiles');
|
|
||||||
theLink = '<?php echo formatLink('{{FILE}}'); ?>';
|
|
||||||
|
|
||||||
var uploader = new ss.SimpleUpload({
|
|
||||||
button: btn,
|
|
||||||
url: 'extras/file_upload.php',
|
|
||||||
name: 'uploadfile',
|
|
||||||
hoverClass: 'hover',
|
|
||||||
multiple: true,
|
|
||||||
focusClass: 'focus',
|
|
||||||
responseType: 'json',
|
|
||||||
startXHR: function() {
|
|
||||||
progressOuter.style.display = 'block'; // make progress bar visible
|
|
||||||
this.setProgressBar( progressBar );
|
|
||||||
},
|
|
||||||
onSubmit: function() {
|
|
||||||
msgBox.innerHTML = ''; // empty the message box
|
|
||||||
btn.innerHTML = 'Uploading...'; // change button text to "Uploading..."
|
|
||||||
},
|
|
||||||
onComplete: function( filename, response ) {
|
|
||||||
btn.innerHTML = 'Choose Files';
|
|
||||||
progressOuter.style.display = 'none'; // hide progress bar when upload is completed
|
|
||||||
|
|
||||||
if ( !response ) {
|
|
||||||
msgBox.innerHTML = 'Unable to upload file';
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( response.success === true ) {
|
|
||||||
msgBox.innerHTML = '<strong>' + escapeTags( filename ) + '</strong>' + ' successfully uploaded.';
|
|
||||||
uploadedFiles.innerHTML = '<div class="highlight">' + replaceAll(theLink, '{{FILE}}', filename) + '</div>' + uploadedFiles.innerHTML ;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if ( response.msg ) {
|
|
||||||
msgBox.innerHTML = escapeTags( response.msg );
|
|
||||||
|
|
||||||
} else {
|
|
||||||
msgBox.innerHTML = 'An error occurred and the upload failed.';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onError: function() {
|
|
||||||
progressOuter.style.display = 'none';
|
|
||||||
msgBox.innerHTML = 'Unable to upload file';
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
Antony Dovgal, Mikael Johansson
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
--------------------------------------------------------------------
|
|
||||||
The PHP License, Version 3.0
|
|
||||||
Copyright (c) 1999 - 2005 The PHP Group. All rights reserved.
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, is permitted provided that the following conditions
|
|
||||||
are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in
|
|
||||||
the documentation and/or other materials provided with the
|
|
||||||
distribution.
|
|
||||||
|
|
||||||
3. The name "PHP" must not be used to endorse or promote products
|
|
||||||
derived from this software without prior written permission. For
|
|
||||||
written permission, please contact group@php.net.
|
|
||||||
|
|
||||||
4. Products derived from this software may not be called "PHP", nor
|
|
||||||
may "PHP" appear in their name, without prior written permission
|
|
||||||
from group@php.net. You may indicate that your software works in
|
|
||||||
conjunction with PHP by saying "Foo for PHP" instead of calling
|
|
||||||
it "PHP Foo" or "phpfoo"
|
|
||||||
|
|
||||||
5. The PHP Group may publish revised and/or new versions of the
|
|
||||||
license from time to time. Each version will be given a
|
|
||||||
distinguishing version number.
|
|
||||||
Once covered code has been published under a particular version
|
|
||||||
of the license, you may always continue to use it under the terms
|
|
||||||
of that version. You may also choose to use such covered code
|
|
||||||
under the terms of any subsequent version of the license
|
|
||||||
published by the PHP Group. No one other than the PHP Group has
|
|
||||||
the right to modify the terms applicable to covered code created
|
|
||||||
under this License.
|
|
||||||
|
|
||||||
6. Redistributions of any form whatsoever must retain the following
|
|
||||||
acknowledgment:
|
|
||||||
"This product includes PHP, freely available from
|
|
||||||
<http://www.php.net/>".
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
|
|
||||||
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
|
|
||||||
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
||||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
||||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
||||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
||||||
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
||||||
OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
|
|
||||||
--------------------------------------------------------------------
|
|
||||||
|
|
||||||
This software consists of voluntary contributions made by many
|
|
||||||
individuals on behalf of the PHP Group.
|
|
||||||
|
|
||||||
The PHP Group can be contacted via Email at group@php.net.
|
|
||||||
|
|
||||||
For more information on the PHP Group and the PHP project,
|
|
||||||
please see <http://www.php.net>.
|
|
||||||
|
|
||||||
This product includes the Zend Engine, freely available at
|
|
||||||
<http://www.zend.com>.
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
memcached module for PHP
|
|
||||||
------------------------
|
|
||||||
This module requires zlib library, used for on-the-fly data (de)compression.
|
|
||||||
Also, you'll need memcached to use it =)
|
|
||||||
|
|
||||||
The memcached website is here:
|
|
||||||
http://www.danga.com/memcached/
|
|
||||||
|
|
||||||
You will probably need libevent to install memcached:
|
|
||||||
You can download it here: http://www.monkey.org/~provos/libevent/
|
|
||||||
|
|
||||||
How to run tests:
|
|
||||||
1. sh tests/memcache.sh
|
|
||||||
2. TEST_PHP_EXECUTABLE=/usr/local/bin/php php -dextension=modules/memcache.so run-tests.php -d extension=modules/memcache.so
|
|
||||||
|
|
||||||
|
|
||||||
New API in 3.0
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
Version 3 introduces a new class "MemcachePool" which implements the new API, the
|
|
||||||
old class "Memcache" is still retained (but is deprecated) with the same interface
|
|
||||||
for backwards compatibility. Please note that you need a new memcached version to
|
|
||||||
use the CAS, default value to increment/decrement, append and prepend, and binary
|
|
||||||
protocol features.
|
|
||||||
|
|
||||||
New INI directives are available to allow control over protocol, redundancy and hash
|
|
||||||
strategy selection. These are
|
|
||||||
|
|
||||||
# The binary protocol results in less traffic and is more efficient
|
|
||||||
# for the client and server to generate/parse
|
|
||||||
|
|
||||||
memcache.protocol = {ascii, binary} # default ascii
|
|
||||||
|
|
||||||
# When enabled the client sends requests to N servers in parallel, resulting in
|
|
||||||
# a somewhat crude reduncancy or mirroring, suitable when used as a session
|
|
||||||
# storage.
|
|
||||||
#
|
|
||||||
# If data integrity is of greater importance a real replicating memcached
|
|
||||||
# backend such as "repcached" (http://sourceforge.net/projects/repcached/) is
|
|
||||||
# recommended
|
|
||||||
|
|
||||||
memcache.redundancy = <int> # default 1
|
|
||||||
memcache.session_redundancy = <int> # default 2
|
|
||||||
|
|
||||||
# Hash strategy and function selection. The consistent hashing strategy
|
|
||||||
# is now the default as it allows servers to be added and removed from
|
|
||||||
# the pool without resulting in all or most keys being re-mapped to
|
|
||||||
# other server (ie. voiding the cache)
|
|
||||||
|
|
||||||
memcache.hash_strategy = {standard, consistent} # default consistent
|
|
||||||
memcache.hash_function = {crc32, fnv} # default crc32
|
|
||||||
|
|
||||||
# Compression is enabled by default, the threshold which control the minimum
|
|
||||||
# string length which triggers compresssion can be changed as
|
|
||||||
|
|
||||||
memcache.compress_threshold = <int> # default 20000
|
|
||||||
|
|
||||||
|
|
||||||
The directives are used by the MemcachePool constructor so you can instantiate
|
|
||||||
several pools with different settings by using ini_set() creativly. For example
|
|
||||||
|
|
||||||
ini_set('memcache.protocol', 'binary');
|
|
||||||
|
|
||||||
$binarypool = new MemcachePool();
|
|
||||||
$binarypool->addServer(...)
|
|
||||||
|
|
||||||
ini_set('memcache.protocol', 'ascii');
|
|
||||||
ini_set('memcache.redundancy', '2');
|
|
||||||
|
|
||||||
$redundantpool = new MemcachePool();
|
|
||||||
$redundantpool->addServer(...)
|
|
||||||
|
|
||||||
ini_set('memcache.redundancy', '1');
|
|
||||||
|
|
||||||
|
|
||||||
The new interface looks like
|
|
||||||
|
|
||||||
class MemcachePool() {
|
|
||||||
bool connect(string host, int tcp_port = 11211, int udp_port = 0, bool persistent = true, int weight = 1, int timeout = 1, int retry_interval = 15)
|
|
||||||
bool addServer(string host, int tcp_port = 11211, int udp_port = 0, bool persistent = true, int weight = 1, int timeout = 1, int retry_interval = 15, bool status = true)
|
|
||||||
bool setServerParams(string host, int tcp_port = 11211, int timeout = 1, int retry_interval = 15, bool status = true)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Supports fetching flags and CAS values
|
|
||||||
*/
|
|
||||||
mixed get(mixed key, mixed &flags = null, mixed &cas = null)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Supports multi-set, for example
|
|
||||||
* $memcache->set(array('key1' => 'val1', 'key2' => 'val1'), null, 0, 60)
|
|
||||||
*/
|
|
||||||
bool add(mixed key, mixed var = null, int flag = 0, int exptime = 0)
|
|
||||||
bool set(mixed key, mixed var = null, int flag = 0, int exptime = 0)
|
|
||||||
bool replace(mixed key, mixed var = null, int flag = 0, int exptime = 0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compare-and-Swap, uses the CAS param from MemcachePool::get()
|
|
||||||
*/
|
|
||||||
bool cas(mixed key, mixed var = null, int flag = 0, int exptime = 0, int cas = 0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepends/appends a value to an existing one
|
|
||||||
*/
|
|
||||||
bool append(mixed key, mixed var = null, int flag = 0, int exptime = 0)
|
|
||||||
bool prepend(mixed key, mixed var = null, int flag = 0, int exptime = 0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Supports multi-key operations, for example
|
|
||||||
* $memcache->delete(array('key1', 'key2'))
|
|
||||||
*/
|
|
||||||
bool delete(mixed key, int exptime = 0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Supports multi-key operations, for example
|
|
||||||
* $memcache->increment(array('key1', 'key2'), 1, 0, 0)
|
|
||||||
*
|
|
||||||
* The new defval (default value) and exptime (expiration time) are used
|
|
||||||
* if the key doesn't already exist. They must be supplied (even if 0) for
|
|
||||||
* this to be enabled.
|
|
||||||
*
|
|
||||||
* Returns an integer with the new value if key is a string
|
|
||||||
* Returns an array of integers if the key is an array
|
|
||||||
*/
|
|
||||||
mixed increment(mixed key, int value = 1, int defval = 0, int exptime = 0)
|
|
||||||
mixed decrement(mixed key, int value = 1, int defval = 0, int exptime = 0)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Assigns a pool-specific failure callback which will be called when
|
|
||||||
* a request fails. May be null in order to disable callbacks. The callback
|
|
||||||
* receive arguments like
|
|
||||||
*
|
|
||||||
* function mycallback($host, $tcp_port, $udp_port, $error, $errnum)
|
|
||||||
*
|
|
||||||
* Where $host and $error are strings or null, the other params are integers.
|
|
||||||
*/
|
|
||||||
bool setFailureCallback(function callback)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locates the server a given would be hashed to
|
|
||||||
*
|
|
||||||
* Returns a string "hostname:port" on success
|
|
||||||
* Returns false on failure such as invalid key
|
|
||||||
*/
|
|
||||||
string findServer(string key)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Maintainers:
|
|
||||||
Herman J. Radtke III hradtke at php dot net
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
$memcache = memcache_connect('localhost', 11211);
|
|
||||||
|
|
||||||
if ($memcache) {
|
|
||||||
$memcache->set("str_key", "String to store in memcached");
|
|
||||||
$memcache->set("num_key", 123);
|
|
||||||
|
|
||||||
$object = new StdClass;
|
|
||||||
$object->attribute = 'test';
|
|
||||||
$memcache->set("obj_key", $object);
|
|
||||||
|
|
||||||
$array = Array('assoc'=>123, 345, 567);
|
|
||||||
$memcache->set("arr_key", $array);
|
|
||||||
|
|
||||||
var_dump($memcache->get('str_key'));
|
|
||||||
var_dump($memcache->get('num_key'));
|
|
||||||
var_dump($memcache->get('obj_key'));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
echo "Connection to memcached failed";
|
|
||||||
}
|
|
||||||
?>
|
|
||||||
|
|
||||||
@@ -1,900 +0,0 @@
|
|||||||
<?php
|
|
||||||
/*
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
| PHP Version 5 |
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
| Copyright (c) 1997-2004 The PHP Group |
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
| This source file is subject to version 3.0 of the PHP license, |
|
|
||||||
| that is bundled with this package in the file LICENSE, and is |
|
|
||||||
| available through the world-wide-web at the following url: |
|
|
||||||
| http://www.php.net/license/3_0.txt. |
|
|
||||||
| If you did not receive a copy of the PHP license and are unable to |
|
|
||||||
| obtain it through the world-wide-web, please send a note to |
|
|
||||||
| license@php.net so we can mail you a copy immediately. |
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
| Author: Harun Yayli <harunyayli at gmail.com> |
|
|
||||||
+----------------------------------------------------------------------+
|
|
||||||
*/
|
|
||||||
|
|
||||||
$VERSION='$Id: memcache.php 326707 2012-07-19 19:02:42Z ab $';
|
|
||||||
|
|
||||||
define('ADMIN_USERNAME','mem'); // Admin Username
|
|
||||||
define('ADMIN_PASSWORD','1'); // Admin Password
|
|
||||||
define('DATE_FORMAT','Y/m/d H:i:s');
|
|
||||||
define('GRAPH_SIZE',200);
|
|
||||||
define('MAX_ITEM_DUMP',50);
|
|
||||||
|
|
||||||
$MEMCACHE_SERVERS[] = 'localhost:11211'; // add more as an array
|
|
||||||
//$MEMCACHE_SERVERS[] = 'mymemcache-server2:11211'; // add more as an array
|
|
||||||
|
|
||||||
|
|
||||||
////////// END OF DEFAULT CONFIG AREA /////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
///////////////// Password protect ////////////////////////////////////////////////////////////////
|
|
||||||
if (!isset($_SERVER['PHP_AUTH_USER']) || !isset($_SERVER['PHP_AUTH_PW']) ||
|
|
||||||
$_SERVER['PHP_AUTH_USER'] != ADMIN_USERNAME ||$_SERVER['PHP_AUTH_PW'] != ADMIN_PASSWORD) {
|
|
||||||
Header("WWW-Authenticate: Basic realm=\"Memcache Login (Username: ".ADMIN_USERNAME."/Password: ".ADMIN_PASSWORD.")\"");
|
|
||||||
Header("HTTP/1.0 401 Unauthorized");
|
|
||||||
|
|
||||||
echo <<<EOB
|
|
||||||
<html><body>
|
|
||||||
<h1>Rejected!</h1>
|
|
||||||
<big>Wrong Username or Password!</big>
|
|
||||||
</body></html>
|
|
||||||
EOB;
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////MEMCACHE FUNCTIONS /////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
function get_host_port_from_server($server){
|
|
||||||
$values = explode(':', $server);
|
|
||||||
if (($values[0] == 'unix') && (!is_numeric( $values[1]))) {
|
|
||||||
return array($server, 0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return $values;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendMemcacheCommands($command){
|
|
||||||
global $MEMCACHE_SERVERS;
|
|
||||||
$result = array();
|
|
||||||
|
|
||||||
foreach($MEMCACHE_SERVERS as $server){
|
|
||||||
$strs = get_host_port_from_server($server);
|
|
||||||
$host = $strs[0];
|
|
||||||
$port = $strs[1];
|
|
||||||
$result[$server] = sendMemcacheCommand($host,$port,$command);
|
|
||||||
}
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
function sendMemcacheCommand($server,$port,$command){
|
|
||||||
|
|
||||||
$s = @fsockopen($server,$port);
|
|
||||||
if (!$s){
|
|
||||||
die("Cant connect to:".$server.':'.$port);
|
|
||||||
}
|
|
||||||
|
|
||||||
fwrite($s, $command."\r\n");
|
|
||||||
|
|
||||||
$buf='';
|
|
||||||
while ((!feof($s))) {
|
|
||||||
$buf .= fgets($s, 256);
|
|
||||||
if (strpos($buf,"END\r\n")!==false){ // stat says end
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (strpos($buf,"DELETED\r\n")!==false || strpos($buf,"NOT_FOUND\r\n")!==false){ // delete says these
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (strpos($buf,"OK\r\n")!==false){ // flush_all says ok
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fclose($s);
|
|
||||||
return parseMemcacheResults($buf);
|
|
||||||
}
|
|
||||||
function parseMemcacheResults($str){
|
|
||||||
|
|
||||||
$res = array();
|
|
||||||
$lines = explode("\r\n",$str);
|
|
||||||
$cnt = count($lines);
|
|
||||||
for($i=0; $i< $cnt; $i++){
|
|
||||||
$line = $lines[$i];
|
|
||||||
$l = explode(' ',$line,3);
|
|
||||||
if (count($l)==3){
|
|
||||||
$res[$l[0]][$l[1]]=$l[2];
|
|
||||||
if ($l[0]=='VALUE'){ // next line is the value
|
|
||||||
$res[$l[0]][$l[1]] = array();
|
|
||||||
list ($flag,$size)=explode(' ',$l[2]);
|
|
||||||
$res[$l[0]][$l[1]]['stat']=array('flag'=>$flag,'size'=>$size);
|
|
||||||
$res[$l[0]][$l[1]]['value']=$lines[++$i];
|
|
||||||
}
|
|
||||||
}elseif($line=='DELETED' || $line=='NOT_FOUND' || $line=='OK'){
|
|
||||||
return $line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $res;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function dumpCacheSlab($server,$slabId,$limit){
|
|
||||||
list($host,$port) = get_host_port_from_server($server);
|
|
||||||
$resp = sendMemcacheCommand($host,$port,'stats cachedump '.$slabId.' '.$limit);
|
|
||||||
|
|
||||||
return $resp;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function flushServer($server){
|
|
||||||
list($host,$port) = get_host_port_from_server($server);
|
|
||||||
$resp = sendMemcacheCommand($host,$port,'flush_all');
|
|
||||||
return $resp;
|
|
||||||
}
|
|
||||||
function getCacheItems(){
|
|
||||||
$items = sendMemcacheCommands('stats items');
|
|
||||||
$serverItems = array();
|
|
||||||
$totalItems = array();
|
|
||||||
foreach ($items as $server=>$itemlist){
|
|
||||||
$serverItems[$server] = array();
|
|
||||||
$totalItems[$server]=0;
|
|
||||||
if (!isset($itemlist['STAT'])){
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$iteminfo = $itemlist['STAT'];
|
|
||||||
|
|
||||||
foreach($iteminfo as $keyinfo=>$value){
|
|
||||||
if (preg_match('/items\:(\d+?)\:(.+?)$/',$keyinfo,$matches)){
|
|
||||||
$serverItems[$server][$matches[1]][$matches[2]] = $value;
|
|
||||||
if ($matches[2]=='number'){
|
|
||||||
$totalItems[$server] +=$value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return array('items'=>$serverItems,'counts'=>$totalItems);
|
|
||||||
}
|
|
||||||
function getMemcacheStats($total=true){
|
|
||||||
$resp = sendMemcacheCommands('stats');
|
|
||||||
if ($total){
|
|
||||||
$res = array();
|
|
||||||
foreach($resp as $server=>$r){
|
|
||||||
foreach($r['STAT'] as $key=>$row){
|
|
||||||
if (!isset($res[$key])){
|
|
||||||
$res[$key]=null;
|
|
||||||
}
|
|
||||||
switch ($key){
|
|
||||||
case 'pid':
|
|
||||||
$res['pid'][$server]=$row;
|
|
||||||
break;
|
|
||||||
case 'uptime':
|
|
||||||
$res['uptime'][$server]=$row;
|
|
||||||
break;
|
|
||||||
case 'time':
|
|
||||||
$res['time'][$server]=$row;
|
|
||||||
break;
|
|
||||||
case 'version':
|
|
||||||
$res['version'][$server]=$row;
|
|
||||||
break;
|
|
||||||
case 'pointer_size':
|
|
||||||
$res['pointer_size'][$server]=$row;
|
|
||||||
break;
|
|
||||||
case 'rusage_user':
|
|
||||||
$res['rusage_user'][$server]=$row;
|
|
||||||
break;
|
|
||||||
case 'rusage_system':
|
|
||||||
$res['rusage_system'][$server]=$row;
|
|
||||||
break;
|
|
||||||
case 'curr_items':
|
|
||||||
$res['curr_items']+=$row;
|
|
||||||
break;
|
|
||||||
case 'total_items':
|
|
||||||
$res['total_items']+=$row;
|
|
||||||
break;
|
|
||||||
case 'bytes':
|
|
||||||
$res['bytes']+=$row;
|
|
||||||
break;
|
|
||||||
case 'curr_connections':
|
|
||||||
$res['curr_connections']+=$row;
|
|
||||||
break;
|
|
||||||
case 'total_connections':
|
|
||||||
$res['total_connections']+=$row;
|
|
||||||
break;
|
|
||||||
case 'connection_structures':
|
|
||||||
$res['connection_structures']+=$row;
|
|
||||||
break;
|
|
||||||
case 'cmd_get':
|
|
||||||
$res['cmd_get']+=$row;
|
|
||||||
break;
|
|
||||||
case 'cmd_set':
|
|
||||||
$res['cmd_set']+=$row;
|
|
||||||
break;
|
|
||||||
case 'get_hits':
|
|
||||||
$res['get_hits']+=$row;
|
|
||||||
break;
|
|
||||||
case 'get_misses':
|
|
||||||
$res['get_misses']+=$row;
|
|
||||||
break;
|
|
||||||
case 'evictions':
|
|
||||||
$res['evictions']+=$row;
|
|
||||||
break;
|
|
||||||
case 'bytes_read':
|
|
||||||
$res['bytes_read']+=$row;
|
|
||||||
break;
|
|
||||||
case 'bytes_written':
|
|
||||||
$res['bytes_written']+=$row;
|
|
||||||
break;
|
|
||||||
case 'limit_maxbytes':
|
|
||||||
$res['limit_maxbytes']+=$row;
|
|
||||||
break;
|
|
||||||
case 'threads':
|
|
||||||
$res['rusage_system'][$server]=$row;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $res;
|
|
||||||
}
|
|
||||||
return $resp;
|
|
||||||
}
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
//
|
|
||||||
// don't cache this page
|
|
||||||
//
|
|
||||||
header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
|
|
||||||
header("Cache-Control: post-check=0, pre-check=0", false);
|
|
||||||
header("Pragma: no-cache"); // HTTP/1.0
|
|
||||||
|
|
||||||
function duration($ts) {
|
|
||||||
global $time;
|
|
||||||
$years = (int)((($time - $ts)/(7*86400))/52.177457);
|
|
||||||
$rem = (int)(($time-$ts)-($years * 52.177457 * 7 * 86400));
|
|
||||||
$weeks = (int)(($rem)/(7*86400));
|
|
||||||
$days = (int)(($rem)/86400) - $weeks*7;
|
|
||||||
$hours = (int)(($rem)/3600) - $days*24 - $weeks*7*24;
|
|
||||||
$mins = (int)(($rem)/60) - $hours*60 - $days*24*60 - $weeks*7*24*60;
|
|
||||||
$str = '';
|
|
||||||
if($years==1) $str .= "$years year, ";
|
|
||||||
if($years>1) $str .= "$years years, ";
|
|
||||||
if($weeks==1) $str .= "$weeks week, ";
|
|
||||||
if($weeks>1) $str .= "$weeks weeks, ";
|
|
||||||
if($days==1) $str .= "$days day,";
|
|
||||||
if($days>1) $str .= "$days days,";
|
|
||||||
if($hours == 1) $str .= " $hours hour and";
|
|
||||||
if($hours>1) $str .= " $hours hours and";
|
|
||||||
if($mins == 1) $str .= " 1 minute";
|
|
||||||
else $str .= " $mins minutes";
|
|
||||||
return $str;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create graphics
|
|
||||||
//
|
|
||||||
function graphics_avail() {
|
|
||||||
return extension_loaded('gd');
|
|
||||||
}
|
|
||||||
|
|
||||||
function bsize($s) {
|
|
||||||
foreach (array('','K','M','G') as $i => $k) {
|
|
||||||
if ($s < 1024) break;
|
|
||||||
$s/=1024;
|
|
||||||
}
|
|
||||||
return sprintf("%5.1f %sBytes",$s,$k);
|
|
||||||
}
|
|
||||||
|
|
||||||
// create menu entry
|
|
||||||
function menu_entry($ob,$title) {
|
|
||||||
global $PHP_SELF;
|
|
||||||
if ($ob==$_GET['op']){
|
|
||||||
return "<li><a class=\"child_active\" href=\"$PHP_SELF&op=$ob\">$title</a></li>";
|
|
||||||
}
|
|
||||||
return "<li><a class=\"active\" href=\"$PHP_SELF&op=$ob\">$title</a></li>";
|
|
||||||
}
|
|
||||||
|
|
||||||
function getHeader(){
|
|
||||||
$header = <<<EOB
|
|
||||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
|
|
||||||
<html>
|
|
||||||
<head><title>MEMCACHE INFO</title>
|
|
||||||
<style type="text/css"><!--
|
|
||||||
body { background:white; font-size:100.01%; margin:0; padding:0; }
|
|
||||||
body,p,td,th,input,submit { font-size:0.8em;font-family:arial,helvetica,sans-serif; }
|
|
||||||
* html body {font-size:0.8em}
|
|
||||||
* html p {font-size:0.8em}
|
|
||||||
* html td {font-size:0.8em}
|
|
||||||
* html th {font-size:0.8em}
|
|
||||||
* html input {font-size:0.8em}
|
|
||||||
* html submit {font-size:0.8em}
|
|
||||||
td { vertical-align:top }
|
|
||||||
a { color:black; font-weight:none; text-decoration:none; }
|
|
||||||
a:hover { text-decoration:underline; }
|
|
||||||
div.content { padding:1em 1em 1em 1em; position:absolute; width:97%; z-index:100; }
|
|
||||||
|
|
||||||
h1.memcache { background:rgb(153,153,204); margin:0; padding:0.5em 1em 0.5em 1em; }
|
|
||||||
* html h1.memcache { margin-bottom:-7px; }
|
|
||||||
h1.memcache a:hover { text-decoration:none; color:rgb(90,90,90); }
|
|
||||||
h1.memcache span.logo {
|
|
||||||
background:rgb(119,123,180);
|
|
||||||
color:black;
|
|
||||||
border-right: solid black 1px;
|
|
||||||
border-bottom: solid black 1px;
|
|
||||||
font-style:italic;
|
|
||||||
font-size:1em;
|
|
||||||
padding-left:1.2em;
|
|
||||||
padding-right:1.2em;
|
|
||||||
text-align:right;
|
|
||||||
display:block;
|
|
||||||
width:130px;
|
|
||||||
}
|
|
||||||
h1.memcache span.logo span.name { color:white; font-size:0.7em; padding:0 0.8em 0 2em; }
|
|
||||||
h1.memcache span.nameinfo { color:white; display:inline; font-size:0.4em; margin-left: 3em; }
|
|
||||||
h1.memcache div.copy { color:black; font-size:0.4em; position:absolute; right:1em; }
|
|
||||||
hr.memcache {
|
|
||||||
background:white;
|
|
||||||
border-bottom:solid rgb(102,102,153) 1px;
|
|
||||||
border-style:none;
|
|
||||||
border-top:solid rgb(102,102,153) 10px;
|
|
||||||
height:12px;
|
|
||||||
margin:0;
|
|
||||||
margin-top:1px;
|
|
||||||
padding:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol,menu { margin:1em 0 0 0; padding:0.2em; margin-left:1em;}
|
|
||||||
ol.menu li { display:inline; margin-right:0.7em; list-style:none; font-size:85%}
|
|
||||||
ol.menu a {
|
|
||||||
background:rgb(153,153,204);
|
|
||||||
border:solid rgb(102,102,153) 2px;
|
|
||||||
color:white;
|
|
||||||
font-weight:bold;
|
|
||||||
margin-right:0em;
|
|
||||||
padding:0.1em 0.5em 0.1em 0.5em;
|
|
||||||
text-decoration:none;
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
ol.menu a.child_active {
|
|
||||||
background:rgb(153,153,204);
|
|
||||||
border:solid rgb(102,102,153) 2px;
|
|
||||||
color:white;
|
|
||||||
font-weight:bold;
|
|
||||||
margin-right:0em;
|
|
||||||
padding:0.1em 0.5em 0.1em 0.5em;
|
|
||||||
text-decoration:none;
|
|
||||||
border-left: solid black 5px;
|
|
||||||
margin-left: 0px;
|
|
||||||
}
|
|
||||||
ol.menu span.active {
|
|
||||||
background:rgb(153,153,204);
|
|
||||||
border:solid rgb(102,102,153) 2px;
|
|
||||||
color:black;
|
|
||||||
font-weight:bold;
|
|
||||||
margin-right:0em;
|
|
||||||
padding:0.1em 0.5em 0.1em 0.5em;
|
|
||||||
text-decoration:none;
|
|
||||||
border-left: solid black 5px;
|
|
||||||
}
|
|
||||||
ol.menu span.inactive {
|
|
||||||
background:rgb(193,193,244);
|
|
||||||
border:solid rgb(182,182,233) 2px;
|
|
||||||
color:white;
|
|
||||||
font-weight:bold;
|
|
||||||
margin-right:0em;
|
|
||||||
padding:0.1em 0.5em 0.1em 0.5em;
|
|
||||||
text-decoration:none;
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
ol.menu a:hover {
|
|
||||||
background:rgb(193,193,244);
|
|
||||||
text-decoration:none;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
div.info {
|
|
||||||
background:rgb(204,204,204);
|
|
||||||
border:solid rgb(204,204,204) 1px;
|
|
||||||
margin-bottom:1em;
|
|
||||||
}
|
|
||||||
div.info h2 {
|
|
||||||
background:rgb(204,204,204);
|
|
||||||
color:black;
|
|
||||||
font-size:1em;
|
|
||||||
margin:0;
|
|
||||||
padding:0.1em 1em 0.1em 1em;
|
|
||||||
}
|
|
||||||
div.info table {
|
|
||||||
border:solid rgb(204,204,204) 1px;
|
|
||||||
border-spacing:0;
|
|
||||||
width:100%;
|
|
||||||
}
|
|
||||||
div.info table th {
|
|
||||||
background:rgb(204,204,204);
|
|
||||||
color:white;
|
|
||||||
margin:0;
|
|
||||||
padding:0.1em 1em 0.1em 1em;
|
|
||||||
}
|
|
||||||
div.info table th a.sortable { color:black; }
|
|
||||||
div.info table tr.tr-0 { background:rgb(238,238,238); }
|
|
||||||
div.info table tr.tr-1 { background:rgb(221,221,221); }
|
|
||||||
div.info table td { padding:0.3em 1em 0.3em 1em; }
|
|
||||||
div.info table td.td-0 { border-right:solid rgb(102,102,153) 1px; white-space:nowrap; }
|
|
||||||
div.info table td.td-n { border-right:solid rgb(102,102,153) 1px; }
|
|
||||||
div.info table td h3 {
|
|
||||||
color:black;
|
|
||||||
font-size:1.1em;
|
|
||||||
margin-left:-0.3em;
|
|
||||||
}
|
|
||||||
.td-0 a , .td-n a, .tr-0 a , tr-1 a {
|
|
||||||
text-decoration:underline;
|
|
||||||
}
|
|
||||||
div.graph { margin-bottom:1em }
|
|
||||||
div.graph h2 { background:rgb(204,204,204);; color:black; font-size:1em; margin:0; padding:0.1em 1em 0.1em 1em; }
|
|
||||||
div.graph table { border:solid rgb(204,204,204) 1px; color:black; font-weight:normal; width:100%; }
|
|
||||||
div.graph table td.td-0 { background:rgb(238,238,238); }
|
|
||||||
div.graph table td.td-1 { background:rgb(221,221,221); }
|
|
||||||
div.graph table td { padding:0.2em 1em 0.4em 1em; }
|
|
||||||
|
|
||||||
div.div1,div.div2 { margin-bottom:1em; width:35em; }
|
|
||||||
div.div3 { position:absolute; left:40em; top:1em; width:580px; }
|
|
||||||
//div.div3 { position:absolute; left:37em; top:1em; right:1em; }
|
|
||||||
|
|
||||||
div.sorting { margin:1.5em 0em 1.5em 2em }
|
|
||||||
.center { text-align:center }
|
|
||||||
.aright { position:absolute;right:1em }
|
|
||||||
.right { text-align:right }
|
|
||||||
.ok { color:rgb(0,200,0); font-weight:bold}
|
|
||||||
.failed { color:rgb(200,0,0); font-weight:bold}
|
|
||||||
|
|
||||||
span.box {
|
|
||||||
border: black solid 1px;
|
|
||||||
border-right:solid black 2px;
|
|
||||||
border-bottom:solid black 2px;
|
|
||||||
padding:0 0.5em 0 0.5em;
|
|
||||||
margin-right:1em;
|
|
||||||
}
|
|
||||||
span.green { background:#60F060; padding:0 0.5em 0 0.5em}
|
|
||||||
span.red { background:#D06030; padding:0 0.5em 0 0.5em }
|
|
||||||
|
|
||||||
div.authneeded {
|
|
||||||
background:rgb(238,238,238);
|
|
||||||
border:solid rgb(204,204,204) 1px;
|
|
||||||
color:rgb(200,0,0);
|
|
||||||
font-size:1.2em;
|
|
||||||
font-weight:bold;
|
|
||||||
padding:2em;
|
|
||||||
text-align:center;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
background:rgb(153,153,204);
|
|
||||||
border:solid rgb(102,102,153) 2px;
|
|
||||||
color:white;
|
|
||||||
font-weight:bold;
|
|
||||||
margin-right:1em;
|
|
||||||
padding:0.1em 0.5em 0.1em 0.5em;
|
|
||||||
}
|
|
||||||
//-->
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="head">
|
|
||||||
<h1 class="memcache">
|
|
||||||
<span class="logo"><a href="http://pecl.php.net/package/memcache">memcache</a></span>
|
|
||||||
<span class="nameinfo">memcache.php by <a href="http://livebookmark.net">Harun Yayli</a></span>
|
|
||||||
</h1>
|
|
||||||
<hr class="memcache">
|
|
||||||
</div>
|
|
||||||
<div class=content>
|
|
||||||
EOB;
|
|
||||||
|
|
||||||
return $header;
|
|
||||||
}
|
|
||||||
function getFooter(){
|
|
||||||
global $VERSION;
|
|
||||||
$footer = '</div><!-- Based on apc.php '.$VERSION.'--></body>
|
|
||||||
</html>
|
|
||||||
';
|
|
||||||
|
|
||||||
return $footer;
|
|
||||||
|
|
||||||
}
|
|
||||||
function getMenu(){
|
|
||||||
global $PHP_SELF;
|
|
||||||
echo "<ol class=menu>";
|
|
||||||
if ($_GET['op']!=4){
|
|
||||||
echo <<<EOB
|
|
||||||
<li><a href="$PHP_SELF&op={$_GET['op']}">Refresh Data</a></li>
|
|
||||||
EOB;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
echo <<<EOB
|
|
||||||
<li><a href="$PHP_SELF&op=2}">Back</a></li>
|
|
||||||
EOB;
|
|
||||||
}
|
|
||||||
echo
|
|
||||||
menu_entry(1,'View Host Stats'),
|
|
||||||
menu_entry(2,'Variables');
|
|
||||||
|
|
||||||
echo <<<EOB
|
|
||||||
</ol>
|
|
||||||
<br/>
|
|
||||||
EOB;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO, AUTH
|
|
||||||
|
|
||||||
$_GET['op'] = !isset($_GET['op'])? '1':$_GET['op'];
|
|
||||||
$PHP_SELF= isset($_SERVER['PHP_SELF']) ? htmlentities(strip_tags($_SERVER['PHP_SELF'],'')) : '';
|
|
||||||
|
|
||||||
$PHP_SELF=$PHP_SELF.'?';
|
|
||||||
$time = time();
|
|
||||||
// sanitize _GET
|
|
||||||
|
|
||||||
foreach($_GET as $key=>$g){
|
|
||||||
$_GET[$key]=htmlentities($g);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// singleout
|
|
||||||
// when singleout is set, it only gives details for that server.
|
|
||||||
if (isset($_GET['singleout']) && $_GET['singleout']>=0 && $_GET['singleout'] <count($MEMCACHE_SERVERS)){
|
|
||||||
$MEMCACHE_SERVERS = array($MEMCACHE_SERVERS[$_GET['singleout']]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// display images
|
|
||||||
if (isset($_GET['IMG'])){
|
|
||||||
$memcacheStats = getMemcacheStats();
|
|
||||||
$memcacheStatsSingle = getMemcacheStats(false);
|
|
||||||
|
|
||||||
if (!graphics_avail()) {
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function fill_box($im, $x, $y, $w, $h, $color1, $color2,$text='',$placeindex='') {
|
|
||||||
global $col_black;
|
|
||||||
$x1=$x+$w-1;
|
|
||||||
$y1=$y+$h-1;
|
|
||||||
|
|
||||||
imagerectangle($im, $x, $y1, $x1+1, $y+1, $col_black);
|
|
||||||
if($y1>$y) imagefilledrectangle($im, $x, $y, $x1, $y1, $color2);
|
|
||||||
else imagefilledrectangle($im, $x, $y1, $x1, $y, $color2);
|
|
||||||
imagerectangle($im, $x, $y1, $x1, $y, $color1);
|
|
||||||
if ($text) {
|
|
||||||
if ($placeindex>0) {
|
|
||||||
|
|
||||||
if ($placeindex<16)
|
|
||||||
{
|
|
||||||
$px=5;
|
|
||||||
$py=$placeindex*12+6;
|
|
||||||
imagefilledrectangle($im, $px+90, $py+3, $px+90-4, $py-3, $color2);
|
|
||||||
imageline($im,$x,$y+$h/2,$px+90,$py,$color2);
|
|
||||||
imagestring($im,2,$px,$py-6,$text,$color1);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if ($placeindex<31) {
|
|
||||||
$px=$x+40*2;
|
|
||||||
$py=($placeindex-15)*12+6;
|
|
||||||
} else {
|
|
||||||
$px=$x+40*2+100*intval(($placeindex-15)/15);
|
|
||||||
$py=($placeindex%15)*12+6;
|
|
||||||
}
|
|
||||||
imagefilledrectangle($im, $px, $py+3, $px-4, $py-3, $color2);
|
|
||||||
imageline($im,$x+$w,$y+$h/2,$px,$py,$color2);
|
|
||||||
imagestring($im,2,$px+2,$py-6,$text,$color1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
imagestring($im,4,$x+5,$y1-16,$text,$color1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function fill_arc($im, $centerX, $centerY, $diameter, $start, $end, $color1,$color2,$text='',$placeindex=0) {
|
|
||||||
$r=$diameter/2;
|
|
||||||
$w=deg2rad((360+$start+($end-$start)/2)%360);
|
|
||||||
|
|
||||||
|
|
||||||
if (function_exists("imagefilledarc")) {
|
|
||||||
// exists only if GD 2.0.1 is avaliable
|
|
||||||
imagefilledarc($im, $centerX+1, $centerY+1, $diameter, $diameter, $start, $end, $color1, IMG_ARC_PIE);
|
|
||||||
imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2, IMG_ARC_PIE);
|
|
||||||
imagefilledarc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color1, IMG_ARC_NOFILL|IMG_ARC_EDGED);
|
|
||||||
} else {
|
|
||||||
imagearc($im, $centerX, $centerY, $diameter, $diameter, $start, $end, $color2);
|
|
||||||
imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2);
|
|
||||||
imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($start+1)) * $r, $centerY + sin(deg2rad($start)) * $r, $color2);
|
|
||||||
imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end-1)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2);
|
|
||||||
imageline($im, $centerX, $centerY, $centerX + cos(deg2rad($end)) * $r, $centerY + sin(deg2rad($end)) * $r, $color2);
|
|
||||||
imagefill($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2, $color2);
|
|
||||||
}
|
|
||||||
if ($text) {
|
|
||||||
if ($placeindex>0) {
|
|
||||||
imageline($im,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$diameter, $placeindex*12,$color1);
|
|
||||||
imagestring($im,4,$diameter, $placeindex*12,$text,$color1);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
imagestring($im,4,$centerX + $r*cos($w)/2, $centerY + $r*sin($w)/2,$text,$color1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$size = GRAPH_SIZE; // image size
|
|
||||||
$image = imagecreate($size+50, $size+10);
|
|
||||||
|
|
||||||
$col_white = imagecolorallocate($image, 0xFF, 0xFF, 0xFF);
|
|
||||||
$col_red = imagecolorallocate($image, 0xD0, 0x60, 0x30);
|
|
||||||
$col_green = imagecolorallocate($image, 0x60, 0xF0, 0x60);
|
|
||||||
$col_black = imagecolorallocate($image, 0, 0, 0);
|
|
||||||
|
|
||||||
imagecolortransparent($image,$col_white);
|
|
||||||
|
|
||||||
switch ($_GET['IMG']){
|
|
||||||
case 1: // pie chart
|
|
||||||
$tsize=$memcacheStats['limit_maxbytes'];
|
|
||||||
$avail=$tsize-$memcacheStats['bytes'];
|
|
||||||
$x=$y=$size/2;
|
|
||||||
$angle_from = 0;
|
|
||||||
$fuzz = 0.000001;
|
|
||||||
|
|
||||||
foreach($memcacheStatsSingle as $serv=>$mcs) {
|
|
||||||
$free = $mcs['STAT']['limit_maxbytes']-$mcs['STAT']['bytes'];
|
|
||||||
$used = $mcs['STAT']['bytes'];
|
|
||||||
|
|
||||||
|
|
||||||
if ($free>0){
|
|
||||||
// draw free
|
|
||||||
$angle_to = ($free*360)/$tsize;
|
|
||||||
$perc =sprintf("%.2f%%", ($free *100) / $tsize) ;
|
|
||||||
|
|
||||||
fill_arc($image,$x,$y,$size,$angle_from,$angle_from + $angle_to ,$col_black,$col_green,$perc);
|
|
||||||
$angle_from = $angle_from + $angle_to ;
|
|
||||||
}
|
|
||||||
if ($used>0){
|
|
||||||
// draw used
|
|
||||||
$angle_to = ($used*360)/$tsize;
|
|
||||||
$perc =sprintf("%.2f%%", ($used *100) / $tsize) ;
|
|
||||||
fill_arc($image,$x,$y,$size,$angle_from,$angle_from + $angle_to ,$col_black,$col_red, '('.$perc.')' );
|
|
||||||
$angle_from = $angle_from+ $angle_to ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: // hit miss
|
|
||||||
|
|
||||||
$hits = ($memcacheStats['get_hits']==0) ? 1:$memcacheStats['get_hits'];
|
|
||||||
$misses = ($memcacheStats['get_misses']==0) ? 1:$memcacheStats['get_misses'];
|
|
||||||
$total = $hits + $misses ;
|
|
||||||
|
|
||||||
fill_box($image, 30,$size,50,-$hits*($size-21)/$total,$col_black,$col_green,sprintf("%.1f%%",$hits*100/$total));
|
|
||||||
fill_box($image,130,$size,50,-max(4,($total-$hits)*($size-21)/$total),$col_black,$col_red,sprintf("%.1f%%",$misses*100/$total));
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
header("Content-type: image/png");
|
|
||||||
imagepng($image);
|
|
||||||
exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
echo getHeader();
|
|
||||||
echo getMenu();
|
|
||||||
|
|
||||||
switch ($_GET['op']) {
|
|
||||||
|
|
||||||
case 1: // host stats
|
|
||||||
$phpversion = phpversion();
|
|
||||||
$memcacheStats = getMemcacheStats();
|
|
||||||
$memcacheStatsSingle = getMemcacheStats(false);
|
|
||||||
|
|
||||||
$mem_size = $memcacheStats['limit_maxbytes'];
|
|
||||||
$mem_used = $memcacheStats['bytes'];
|
|
||||||
$mem_avail= $mem_size-$mem_used;
|
|
||||||
$startTime = time()-array_sum($memcacheStats['uptime']);
|
|
||||||
|
|
||||||
$curr_items = $memcacheStats['curr_items'];
|
|
||||||
$total_items = $memcacheStats['total_items'];
|
|
||||||
$hits = ($memcacheStats['get_hits']==0) ? 1:$memcacheStats['get_hits'];
|
|
||||||
$misses = ($memcacheStats['get_misses']==0) ? 1:$memcacheStats['get_misses'];
|
|
||||||
$sets = $memcacheStats['cmd_set'];
|
|
||||||
|
|
||||||
$req_rate = sprintf("%.2f",($hits+$misses)/($time-$startTime));
|
|
||||||
$hit_rate = sprintf("%.2f",($hits)/($time-$startTime));
|
|
||||||
$miss_rate = sprintf("%.2f",($misses)/($time-$startTime));
|
|
||||||
$set_rate = sprintf("%.2f",($sets)/($time-$startTime));
|
|
||||||
|
|
||||||
echo <<< EOB
|
|
||||||
<div class="info div1"><h2>General Cache Information</h2>
|
|
||||||
<table cellspacing=0><tbody>
|
|
||||||
<tr class=tr-1><td class=td-0>PHP Version</td><td>$phpversion</td></tr>
|
|
||||||
EOB;
|
|
||||||
echo "<tr class=tr-0><td class=td-0>Memcached Host". ((count($MEMCACHE_SERVERS)>1) ? 's':'')."</td><td>";
|
|
||||||
$i=0;
|
|
||||||
if (!isset($_GET['singleout']) && count($MEMCACHE_SERVERS)>1){
|
|
||||||
foreach($MEMCACHE_SERVERS as $server){
|
|
||||||
echo ($i+1).'. <a href="'.$PHP_SELF.'&singleout='.$i++.'">'.$server.'</a><br/>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
echo '1.'.$MEMCACHE_SERVERS[0];
|
|
||||||
}
|
|
||||||
if (isset($_GET['singleout'])){
|
|
||||||
echo '<a href="'.$PHP_SELF.'">(all servers)</a><br/>';
|
|
||||||
}
|
|
||||||
echo "</td></tr>\n";
|
|
||||||
echo "<tr class=tr-1><td class=td-0>Total Memcache Cache</td><td>".bsize($memcacheStats['limit_maxbytes'])."</td></tr>\n";
|
|
||||||
|
|
||||||
echo <<<EOB
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="info div1"><h2>Memcache Server Information</h2>
|
|
||||||
EOB;
|
|
||||||
foreach($MEMCACHE_SERVERS as $server){
|
|
||||||
echo '<table cellspacing=0><tbody>';
|
|
||||||
echo '<tr class=tr-1><td class=td-1>'.$server.'</td><td><a href="'.$PHP_SELF.'&server='.array_search($server,$MEMCACHE_SERVERS).'&op=6">[<b>Flush this server</b>]</a></td></tr>';
|
|
||||||
echo '<tr class=tr-0><td class=td-0>Start Time</td><td>',date(DATE_FORMAT,$memcacheStatsSingle[$server]['STAT']['time']-$memcacheStatsSingle[$server]['STAT']['uptime']),'</td></tr>';
|
|
||||||
echo '<tr class=tr-1><td class=td-0>Uptime</td><td>',duration($memcacheStatsSingle[$server]['STAT']['time']-$memcacheStatsSingle[$server]['STAT']['uptime']),'</td></tr>';
|
|
||||||
echo '<tr class=tr-0><td class=td-0>Memcached Server Version</td><td>'.$memcacheStatsSingle[$server]['STAT']['version'].'</td></tr>';
|
|
||||||
echo '<tr class=tr-1><td class=td-0>Used Cache Size</td><td>',bsize($memcacheStatsSingle[$server]['STAT']['bytes']),'</td></tr>';
|
|
||||||
echo '<tr class=tr-0><td class=td-0>Total Cache Size</td><td>',bsize($memcacheStatsSingle[$server]['STAT']['limit_maxbytes']),'</td></tr>';
|
|
||||||
echo '</tbody></table>';
|
|
||||||
}
|
|
||||||
echo <<<EOB
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div class="graph div3"><h2>Host Status Diagrams</h2>
|
|
||||||
<table cellspacing=0><tbody>
|
|
||||||
EOB;
|
|
||||||
|
|
||||||
$size='width='.(GRAPH_SIZE+50).' height='.(GRAPH_SIZE+10);
|
|
||||||
echo <<<EOB
|
|
||||||
<tr>
|
|
||||||
<td class=td-0>Cache Usage</td>
|
|
||||||
<td class=td-1>Hits & Misses</td>
|
|
||||||
</tr>
|
|
||||||
EOB;
|
|
||||||
|
|
||||||
echo
|
|
||||||
graphics_avail() ?
|
|
||||||
'<tr>'.
|
|
||||||
"<td class=td-0><img alt=\"\" $size src=\"$PHP_SELF&IMG=1&".(isset($_GET['singleout'])? 'singleout='.$_GET['singleout'].'&':'')."$time\"></td>".
|
|
||||||
"<td class=td-1><img alt=\"\" $size src=\"$PHP_SELF&IMG=2&".(isset($_GET['singleout'])? 'singleout='.$_GET['singleout'].'&':'')."$time\"></td></tr>\n"
|
|
||||||
: "",
|
|
||||||
'<tr>',
|
|
||||||
'<td class=td-0><span class="green box"> </span>Free: ',bsize($mem_avail).sprintf(" (%.1f%%)",$mem_avail*100/$mem_size),"</td>\n",
|
|
||||||
'<td class=td-1><span class="green box"> </span>Hits: ',$hits.sprintf(" (%.1f%%)",$hits*100/($hits+$misses)),"</td>\n",
|
|
||||||
'</tr>',
|
|
||||||
'<tr>',
|
|
||||||
'<td class=td-0><span class="red box"> </span>Used: ',bsize($mem_used ).sprintf(" (%.1f%%)",$mem_used *100/$mem_size),"</td>\n",
|
|
||||||
'<td class=td-1><span class="red box"> </span>Misses: ',$misses.sprintf(" (%.1f%%)",$misses*100/($hits+$misses)),"</td>\n";
|
|
||||||
echo <<< EOB
|
|
||||||
</tr>
|
|
||||||
</tbody></table>
|
|
||||||
<br/>
|
|
||||||
<div class="info"><h2>Cache Information</h2>
|
|
||||||
<table cellspacing=0><tbody>
|
|
||||||
<tr class=tr-0><td class=td-0>Current Items(total)</td><td>$curr_items ($total_items)</td></tr>
|
|
||||||
<tr class=tr-1><td class=td-0>Hits</td><td>{$hits}</td></tr>
|
|
||||||
<tr class=tr-0><td class=td-0>Misses</td><td>{$misses}</td></tr>
|
|
||||||
<tr class=tr-1><td class=td-0>Request Rate (hits, misses)</td><td>$req_rate cache requests/second</td></tr>
|
|
||||||
<tr class=tr-0><td class=td-0>Hit Rate</td><td>$hit_rate cache requests/second</td></tr>
|
|
||||||
<tr class=tr-1><td class=td-0>Miss Rate</td><td>$miss_rate cache requests/second</td></tr>
|
|
||||||
<tr class=tr-0><td class=td-0>Set Rate</td><td>$set_rate cache requests/second</td></tr>
|
|
||||||
</tbody></table>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
EOB;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2: // variables
|
|
||||||
|
|
||||||
$m=0;
|
|
||||||
$cacheItems= getCacheItems();
|
|
||||||
$items = $cacheItems['items'];
|
|
||||||
$totals = $cacheItems['counts'];
|
|
||||||
$maxDump = MAX_ITEM_DUMP;
|
|
||||||
foreach($items as $server => $entries) {
|
|
||||||
|
|
||||||
echo <<< EOB
|
|
||||||
|
|
||||||
<div class="info"><table cellspacing=0><tbody>
|
|
||||||
<tr><th colspan="2">$server</th></tr>
|
|
||||||
<tr><th>Slab Id</th><th>Info</th></tr>
|
|
||||||
EOB;
|
|
||||||
|
|
||||||
foreach($entries as $slabId => $slab) {
|
|
||||||
$dumpUrl = $PHP_SELF.'&op=2&server='.(array_search($server,$MEMCACHE_SERVERS)).'&dumpslab='.$slabId;
|
|
||||||
echo
|
|
||||||
"<tr class=tr-$m>",
|
|
||||||
"<td class=td-0><center>",'<a href="',$dumpUrl,'">',$slabId,'</a>',"</center></td>",
|
|
||||||
"<td class=td-last><b>Item count:</b> ",$slab['number'],'<br/><b>Age:</b>',duration($time-$slab['age']),'<br/> <b>Evicted:</b>',((isset($slab['evicted']) && $slab['evicted']==1)? 'Yes':'No');
|
|
||||||
if ((isset($_GET['dumpslab']) && $_GET['dumpslab']==$slabId) && (isset($_GET['server']) && $_GET['server']==array_search($server,$MEMCACHE_SERVERS))){
|
|
||||||
echo "<br/><b>Items: item</b><br/>";
|
|
||||||
$items = dumpCacheSlab($server,$slabId,$slab['number']);
|
|
||||||
// maybe someone likes to do a pagination here :)
|
|
||||||
$i=1;
|
|
||||||
foreach($items['ITEM'] as $itemKey=>$itemInfo){
|
|
||||||
$itemInfo = trim($itemInfo,'[ ]');
|
|
||||||
|
|
||||||
|
|
||||||
echo '<a href="',$PHP_SELF,'&op=4&server=',(array_search($server,$MEMCACHE_SERVERS)),'&key=',base64_encode($itemKey).'">',$itemKey,'</a>';
|
|
||||||
if ($i++ % 10 == 0) {
|
|
||||||
echo '<br/>';
|
|
||||||
}
|
|
||||||
elseif ($i!=$slab['number']+1){
|
|
||||||
echo ',';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echo "</td></tr>";
|
|
||||||
$m=1-$m;
|
|
||||||
}
|
|
||||||
echo <<<EOB
|
|
||||||
</tbody></table>
|
|
||||||
</div><hr/>
|
|
||||||
EOB;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 4: //item dump
|
|
||||||
if (!isset($_GET['key']) || !isset($_GET['server'])){
|
|
||||||
echo "No key set!";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// I'm not doing anything to check the validity of the key string.
|
|
||||||
// probably an exploit can be written to delete all the files in key=base64_encode("\n\r delete all").
|
|
||||||
// somebody has to do a fix to this.
|
|
||||||
$theKey = htmlentities(base64_decode($_GET['key']));
|
|
||||||
|
|
||||||
$theserver = $MEMCACHE_SERVERS[(int)$_GET['server']];
|
|
||||||
list($h,$p) = get_host_port_from_server($theserver);
|
|
||||||
$r = sendMemcacheCommand($h,$p,'get '.$theKey);
|
|
||||||
echo <<<EOB
|
|
||||||
<div class="info"><table cellspacing=0><tbody>
|
|
||||||
<tr><th>Server<th>Key</th><th>Value</th><th>Delete</th></tr>
|
|
||||||
EOB;
|
|
||||||
if (!isset($r['VALUE'])) {
|
|
||||||
echo "<tr><td class=td-0>",$theserver,"</td><td class=td-0>",$theKey,
|
|
||||||
"</td><td>[The requested item was not found or has expired]</td>",
|
|
||||||
"<td></td>","</tr>";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
|
|
||||||
echo "<tr><td class=td-0>",$theserver,"</td><td class=td-0>",$theKey,
|
|
||||||
" <br/>flag:",$r['VALUE'][$theKey]['stat']['flag'],
|
|
||||||
" <br/>Size:",bsize($r['VALUE'][$theKey]['stat']['size']),
|
|
||||||
"</td><td>",chunk_split($r['VALUE'][$theKey]['value'],40),"</td>",
|
|
||||||
'<td><a href="',$PHP_SELF,'&op=5&server=',(int)$_GET['server'],'&key=',base64_encode($theKey),"\">Delete</a></td>","</tr>";
|
|
||||||
}
|
|
||||||
echo <<<EOB
|
|
||||||
</tbody></table>
|
|
||||||
</div><hr/>
|
|
||||||
EOB;
|
|
||||||
break;
|
|
||||||
case 5: // item delete
|
|
||||||
if (!isset($_GET['key']) || !isset($_GET['server'])){
|
|
||||||
echo "No key set!";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$theKey = htmlentities(base64_decode($_GET['key']));
|
|
||||||
$theserver = $MEMCACHE_SERVERS[(int)$_GET['server']];
|
|
||||||
list($h,$p) = get_host_port_from_server($theserver);
|
|
||||||
$r = sendMemcacheCommand($h,$p,'delete '.$theKey);
|
|
||||||
echo 'Deleting '.$theKey.':'.$r;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 6: // flush server
|
|
||||||
$_GET['server'] = empty($_GET['server']) ? 0 : $_GET['server'];
|
|
||||||
$theserver = $MEMCACHE_SERVERS[(int)$_GET['server']];
|
|
||||||
$r = flushServer($theserver);
|
|
||||||
echo 'Flush '.$theserver.":".$r;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
echo getFooter();
|
|
||||||
|
|
||||||
?>
|
|
||||||
Binary file not shown.
@@ -38,14 +38,14 @@ if exist "%USER_DIR%\user.cmd" (
|
|||||||
echo :: call start-ssh-agent.cmd
|
echo :: call start-ssh-agent.cmd
|
||||||
echo :: set PATH=%%USER_DIR%%\bin\whatever;%%PATH%%
|
echo :: set PATH=%%USER_DIR%%\bin\whatever;%%PATH%%
|
||||||
echo.
|
echo.
|
||||||
echo :: cmd /c start http://localhost
|
echo :: cmd /c start http://localhost
|
||||||
echo.
|
echo.
|
||||||
) > "%USER_DIR%\user.cmd"
|
) > "%USER_DIR%\user.cmd"
|
||||||
|
|
||||||
:: cd /d "%CMDER_ROOT%\..\..\www"
|
:: cd /d "%CMDER_ROOT%\..\..\www"
|
||||||
rem
|
rem
|
||||||
)
|
)
|
||||||
|
|
||||||
:: Laragon End -------------------------------------------------------------------
|
:: Laragon End -------------------------------------------------------------------
|
||||||
|
|
||||||
exit /b 0
|
exit /b 0
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ location /adminer {
|
|||||||
|
|
||||||
location ~ ^/adminer/(.+\.php)$ {
|
location ~ ^/adminer/(.+\.php)$ {
|
||||||
alias C:/laragon/etc/apps/adminer/$1;
|
alias C:/laragon/etc/apps/adminer/$1;
|
||||||
fastcgi_pass php_upstream;
|
fastcgi_pass php_upstream;
|
||||||
fastcgi_index index.php;
|
fastcgi_index index.php;
|
||||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
fastcgi_param SCRIPT_FILENAME $request_filename;
|
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ location ~ /laragon/uploads/(.+)\.php$ {
|
|||||||
location ~ ^/laragon/(.+\.php)$ {
|
location ~ ^/laragon/(.+\.php)$ {
|
||||||
allow all;
|
allow all;
|
||||||
alias C:/laragon/etc/apps/laragon/$1;
|
alias C:/laragon/etc/apps/laragon/$1;
|
||||||
fastcgi_pass php_upstream;
|
fastcgi_pass php_upstream;
|
||||||
fastcgi_index index.php;
|
fastcgi_index index.php;
|
||||||
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
fastcgi_split_path_info ^(.+\.php)(/.+)$;
|
||||||
fastcgi_param SCRIPT_FILENAME $request_filename;
|
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ location /memcached {
|
|||||||
alias C:/laragon/etc/apps/memcached/;
|
alias C:/laragon/etc/apps/memcached/;
|
||||||
index index.php;
|
index index.php;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ ^/memcached/(.+\.php)$ {
|
location ~ ^/memcached/(.+\.php)$ {
|
||||||
alias C:/laragon/etc/apps/memcached/$1;
|
alias C:/laragon/etc/apps/memcached/$1;
|
||||||
fastcgi_pass php_upstream;
|
fastcgi_pass php_upstream;
|
||||||
fastcgi_index index.php;
|
fastcgi_index index.php;
|
||||||
fastcgi_param SCRIPT_FILENAME $request_filename;
|
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ location /phpmyadmin {
|
|||||||
alias C:/laragon/etc/apps/phpmyadmin/;
|
alias C:/laragon/etc/apps/phpmyadmin/;
|
||||||
index index.php;
|
index index.php;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
location ~ ^/phpmyadmin/(.+\.php)$ {
|
location ~ ^/phpmyadmin/(.+\.php)$ {
|
||||||
alias C:/laragon/etc/apps/phpmyadmin/$1;
|
alias C:/laragon/etc/apps/phpmyadmin/$1;
|
||||||
fastcgi_pass php_upstream;
|
fastcgi_pass php_upstream;
|
||||||
fastcgi_index index.php;
|
fastcgi_index index.php;
|
||||||
fastcgi_param SCRIPT_FILENAME $request_filename;
|
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ location /redis {
|
|||||||
|
|
||||||
location ~ ^/redis/(.+\.php)$ {
|
location ~ ^/redis/(.+\.php)$ {
|
||||||
alias C:/laragon/etc/apps/phpRedisAdmin/$1;
|
alias C:/laragon/etc/apps/phpRedisAdmin/$1;
|
||||||
fastcgi_pass php_upstream;
|
fastcgi_pass php_upstream;
|
||||||
fastcgi_index index.php;
|
fastcgi_index index.php;
|
||||||
fastcgi_param SCRIPT_FILENAME $request_filename;
|
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||||
|
|
||||||
|
|||||||
@@ -173,9 +173,9 @@ class Memcached
|
|||||||
protected $socket = null;
|
protected $socket = null;
|
||||||
|
|
||||||
public function getVersion() {
|
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
|
//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() {
|
public function setMulti() {
|
||||||
@@ -185,7 +185,7 @@ class Memcached
|
|||||||
//TODO
|
//TODO
|
||||||
die('TODO');
|
die('TODO');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a serer to the server pool
|
* Add a serer to the server pool
|
||||||
*
|
*
|
||||||
@@ -444,7 +444,7 @@ class Memcached
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store an item.
|
* Store an item.
|
||||||
* Fails if $key already exists
|
* Fails if $key already exists
|
||||||
*
|
*
|
||||||
* @param string $key
|
* @param string $key
|
||||||
@@ -464,7 +464,7 @@ class Memcached
|
|||||||
|
|
||||||
if ('STORED' == $s) {
|
if ('STORED' == $s) {
|
||||||
$this->resultCode = Memcached::RES_SUCCESS;
|
$this->resultCode = Memcached::RES_SUCCESS;
|
||||||
$this->resultMessage = '';
|
$this->resultMessage = '';
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
BIN
laragon.exe
BIN
laragon.exe
Binary file not shown.
@@ -9,7 +9,6 @@
|
|||||||
; PWD: Current working directory - where the COMMANDS run
|
; PWD: Current working directory - where the COMMANDS run
|
||||||
|
|
||||||
# Examples:
|
# 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"
|
; Awesome Tool: "PATH HAS SPACES SHOULD BE QUOTED LIKE THIS"
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,6 @@
|
|||||||
; PWD: Current working directory - where the COMMANDS run
|
; PWD: Current working directory - where the COMMANDS run
|
||||||
|
|
||||||
# Examples:
|
# 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"
|
; Awesome Tool: "PATH HAS SPACES SHOULD BE QUOTED LIKE THIS"
|
||||||
------------------------------------------------------------------------------
|
------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,33 @@
|
|||||||
# PHP
|
# PHP
|
||||||
# https://windows.php.net/download/
|
# https://windows.php.net/download/
|
||||||
# NTS = Non Thread Safe
|
# 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.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.15-nts-Win32-vs16-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.27-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.31-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
|
# Node.js
|
||||||
# https://nodejs.org/en/download/prebuilt-binaries/current
|
# 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-23.9=https://nodejs.org/dist/v23.9.0/node-v23.9.0-win-x64.zip
|
||||||
node-22=https://nodejs.org/dist/v22.12.0/node-v22.12.0-win-x64.zip
|
node-22.14=https://nodejs.org/dist/v22.14.0/node-v22.14.0-win-x64.zip
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
||||||
# phpMyAdmin
|
# phpMyAdmin
|
||||||
# After download, visit -> http://localhost/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
|
# DB Tools
|
||||||
DBeaver=https://dbeaver.io/files/dbeaver-ce-latest-win32.win32.x86_64.zip
|
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
|
# https://www.mongodb.com/try/download/community
|
||||||
#mongodb-8=https://fastdl.mongodb.org/windows/mongodb-windows-x86_64-8.0.4.zip
|
#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
|
#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
|
# Golang
|
||||||
# https://go.dev/dl/
|
# 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
|
# Pocketbase
|
||||||
# https://github.com/pocketbase/pocketbase/releases
|
# 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
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
Simplicity is the ultimate sophistication. - Leonardo da Vinci
|
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
|
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
|
The power of imagination makes us infinite. - John Muir
|
||||||
Make each day your masterpiece. - John Wooden
|
Make each day your masterpiece. - John Wooden
|
||||||
Believe and act as if it were impossible to fail. - Charles Kettering
|
Believe and act as if it were impossible to fail. - Charles Kettering
|
||||||
Light tomorrow with today. - Elizabeth Barrett Browning
|
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
|
Believe you can and you're halfway there. - Theodore Roosevelt
|
||||||
Don't wait. The time will never be just right. - Napoleon Hill
|
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
|
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
|
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
|
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
|
What we fear doing most is usually what we most need to do. - Tim Ferriss
|
||||||
|
|||||||
@@ -2,5 +2,32 @@
|
|||||||
AutoCreateDatabase=true
|
AutoCreateDatabase=true
|
||||||
Cached=true
|
Cached=true
|
||||||
|
|
||||||
|
# Blank: an empty project
|
||||||
|
Blank=
|
||||||
|
|
||||||
# WordPress
|
# 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
|
||||||
|
|||||||
232
www/index.php
232
www/index.php
@@ -1,167 +1,105 @@
|
|||||||
<?php
|
<?php
|
||||||
if (!empty($_GET['q'])) {
|
if (!empty($_GET['q'])) {
|
||||||
switch ($_GET['q']) {
|
$query = htmlspecialchars($_GET['q'], ENT_QUOTES, 'UTF-8');
|
||||||
case 'info':
|
|
||||||
phpinfo();
|
switch ($query) {
|
||||||
exit;
|
case 'info':
|
||||||
break;
|
phpinfo();
|
||||||
}
|
exit;
|
||||||
|
default:
|
||||||
|
header("HTTP/1.0 404 Not Found");
|
||||||
|
echo "Invalid query parameter.";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Laragon</title>
|
<title>Laragon</title>
|
||||||
<link href="https://fonts.googleapis.com/css?family=Karla:400" rel="stylesheet" type="text/css">
|
<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>
|
||||||
<style>
|
html, body {
|
||||||
*,
|
height: 100%;
|
||||||
:before *,
|
margin: 0;
|
||||||
:after * {
|
padding: 0;
|
||||||
box-sizing: border-box;
|
font-family: 'Karla', sans-serif;
|
||||||
}
|
font-weight: 100;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
.container {
|
||||||
margin: 0;
|
display: flex;
|
||||||
min-height: 100vh;
|
justify-content: center;
|
||||||
font-weight: 100;
|
align-items: center;
|
||||||
font-family: 'Karla', sans-serif;
|
height: 100%;
|
||||||
font-size: 18px;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
header,
|
.content {
|
||||||
main,
|
max-width: 800px;
|
||||||
nav,
|
padding: 100px;
|
||||||
aside {
|
background: #fff;
|
||||||
padding: 1rem;
|
border-radius: 8px;
|
||||||
margin: auto;
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||||
max-width: 1200px;
|
}
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
.title {
|
||||||
display: flex;
|
font-size: 60px;
|
||||||
flex-wrap: wrap;
|
margin: 0;
|
||||||
justify-content: center;
|
}
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.header__item {
|
.info {
|
||||||
margin: 0;
|
margin-top: 20px;
|
||||||
padding: 1rem;
|
font-size: 18px;
|
||||||
}
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
.header--logo {
|
.info a {
|
||||||
height: 8rem;
|
color: #007bff;
|
||||||
}
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
h1 {
|
.info a:hover {
|
||||||
font-size: 5rem;
|
color: #0056b3;
|
||||||
}
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
main {
|
.opt {
|
||||||
background-color: #f5f5f5;
|
margin-top: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
nav {
|
.opt a {
|
||||||
width: 100%;
|
font-size: 18px;
|
||||||
}
|
color: #007bff;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
ul {
|
.opt a:hover {
|
||||||
list-style: none;
|
color: #0056b3;
|
||||||
padding: 0;
|
text-decoration: underline;
|
||||||
margin: auto;
|
}
|
||||||
}
|
</style>
|
||||||
|
|
||||||
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>
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<div class="container">
|
||||||
<img class="header__item header--logo" src="https://i.imgur.com/ky9oqct.png" alt="Offline">
|
<div class="content">
|
||||||
<h1 class="header__item header--title" title="Laragon">Laragon</h1>
|
<h1 class="title" title="Laragon">Laragon</h1>
|
||||||
</header>
|
<div class="info">
|
||||||
<main>
|
<p><?php echo htmlspecialchars($_SERVER['SERVER_SOFTWARE'], ENT_QUOTES, 'UTF-8'); ?></p>
|
||||||
<p>
|
<p>PHP version: <?php echo htmlspecialchars(phpversion(), ENT_QUOTES, 'UTF-8'); ?>
|
||||||
<?php print($_SERVER['SERVER_SOFTWARE']); ?>
|
<a title="phpinfo()" href="/?q=info">info</a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>Document Root: <?php echo htmlspecialchars($_SERVER['DOCUMENT_ROOT'], ENT_QUOTES, 'UTF-8'); ?></p>
|
||||||
PHP version: <?php print PHP_VERSION; ?> <span><a title="phpinfo()" href="/?q=info">info</a></span>
|
</div>
|
||||||
</p>
|
<div class="opt">
|
||||||
<p>
|
<p><a title="Getting Started" href="https://laragon.org/docs">Getting Started</a></p>
|
||||||
Document Root: <?php print($_SERVER['DOCUMENT_ROOT']); ?>
|
</div>
|
||||||
</p>
|
</div>
|
||||||
<p>
|
</div>
|
||||||
<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;
|
|
||||||
?>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user