A self-hosted, DeepSeek V4βpowered web IDE for editing and live-previewing PHP β right in your browser.
Drop a PHP project into working_folder/, edit it with full syntax highlighting,
ask the AI to explain / rewrite / surgically patch your code, then hit βΆ Preview
to run the PHP server-side and see the real, rendered result.
Author: g023 Β· Editor: Ace (BSD-3, vendored) Β· No CDN β every asset is local.
The entire point of Preview is to execute user-supplied PHP through the web server β that is remote code execution by design, and no PHP setting makes it safe against a stranger. Anyone who can reach this app can run any code on your machine.
Never expose DS PHP Edit on a shared host, a VPS with a public port, a
0.0.0.0bind, or any internet-reachable directory. Every other security control in this app (CSP, CSRF, path sandboxing, upload hardening) is defense-in-depth on top of network isolation β never a substitute for it.
See SECURITY.md for the full threat model. If in doubt, keep it on your laptop.
Drop a PHP project in β open a file β edit it β ask the AI β βΆ Preview β repeat.
| βοΈ Edit real PHP with highlighting, line numbers & AI autocomplete | π€ Ask DeepSeek to explain, rewrite, or patch your code |
| π¦ One-click ZIP backups & safe restore | |
| πΌοΈ Media library with auto-thumbnails & snippet insertion | π 100% local β no CDN, no telemetry, no build step |
π₯ A full walkthrough video is in
screenshot_vids/(ds-php-edit-demo.mp4/.gif).
There is no build step, no installer, no package manager, no setup wizard. Getting the folder onto a PHP host and opening it is the entire deployment.
git clone https://github.com/g023/dsphpedit.git
cd dsphpeditCopy the example key file and paste your sk-... key into it (one line):
cp K.dat.example K.dat
# then edit K.dat and replace the placeholder with your real DeepSeek keyπ Get a key at https://platform.deepseek.com/. The key stays server-side only β it never reaches the browser. Editing and preview work without a key; only the AI features need it.
Option A β built-in PHP server (recommended, easiest localhost binding):
php -S 127.0.0.1:8000 router.php
# open http://127.0.0.1:8000/The router.php front controller blocks direct HTTP access to secrets/state (K.dat, history JSON, backups, dotfiles) and serves vendored assets directly.
Option B β Apache (userdir / vhost / subfolder):
Place the folder under a served path, e.g. ~/public_html/dsphpedit/, and open
http://localhost/~youruser/dsphpedit/. The bundled .htaccess denies K.dat
and dotfiles; working_folder/uploads/.htaccess makes the upload dir
non-executable. The app is path-independent β every server path derives from
__DIR__ and every front-end URL is relative, so it works at any path or location.
π To hard-enforce localhost at the Apache layer: uncomment the
Require ip 127.0.0.1block in.htaccess, or bind Apache'sListento127.0.0.1.
Required runtime directories (working_folder/uploads/, working_folder/g023_backups/, working_folder/g023_history.json, thumbnails) are auto-created on first use β delete them and they come back. A small sample project (welcome.php) is already in working_folder/ so you have something to preview immediately.
- PHP 8.1+ (developed against 8.4). A CLI
phpbinary must be available (used for preview + lint). - PHP extensions β all stock, no PECL/compile:
curl(DeepSeek),gd(thumbnails),zip(backups),fileinfo(upload MIME),mbstring, plusjson/session.
Verify your host before you start:
php tools/selfcheck.php # checks extensions, writable dirs, key, preview capability
php tools/test_paths.php # path-traversal test suite β must be ALL GREEN
php tools/test_features.php # settings / PEEK / agentic-reading suite (in-process assertions)Both also render in a browser (they are localhost-only tools).
β οΈ Theworking_folder/must be writable by the web-server user (e.g.www-dataunder Apache). If saves, uploads, or backups fail with "Write failed," fix the directory permissions.
| Area | What you get |
|---|---|
| Editor | Ace with syntax highlighting + line numbers for PHP / HTML / JS / CSS / JSON / Markdown, language auto-selected by extension, Ctrl+S to save, dirty-state tracking, multi-file tabs with persisted UI state. |
| AI code completion | Copilot-style inline ghost-text suggestions from DeepSeek (flash, fill-in-the-middle using code before and after the cursor). Suggestions are overlap-deduped so they splice in cleanly β any head that re-types the code before the cursor (e.g. a doubled //) or tail that re-types the code after it (doubled ), ;, }, or whole lines) is trimmed server-side. Toggle on/off (Alt+Shift+A or the β¨ Complete control); choose Manual (suggest on Alt+\) or Auto (suggest as you pause). Accept all with β Accept, one word with β word / Alt+], dismiss with Esc. Tab keeps normal indent. Persists per browser. |
| File explorer | Tree scoped to working_folder/; create / rename / delete files & folders; nested dirs; right-click actions. App-managed state is hidden from the picker. |
| Server-side preview | Runs the saved PHP natively through the web server β exactly as it will in production (real $_SERVER, header(), sessions) β and renders output in a same-origin iframe. PHP errors / warnings / fatals are shown. Path-confined to working_folder/; works under Apache/mod_php, PHP-FPM, and php -S. |
| AI assistant | DeepSeek V4. Three modes: Explain (Q&A), Full (whole updated file β Apply full code), Edit (JSON search/replace β Apply edits). Optional Thinking mode surfaces reasoning. Token usage shown. |
| Models | deepseek-v4-flash is the default everywhere (~3Γ cheaper). deepseek-v4-pro is an opt-in selector, never the default. |
| Media | Upload images / PDF / audio / video. Server-side MIME allowlist (finfo), GD re-encode (strips payloads/EXIF), auto thumbnails, randomized filenames, non-executable upload dir. The media browser inserts the right snippet at the cursor. |
| History | Conversations persisted to working_folder/g023_history.json β browsable, reloadable, clearable, rotated. |
| Backup / restore | One-click ZIP of working_folder/ (atomic). Zip-Slip-safe restore (per-entry validation, stream extraction, temp-dir-then-swap). Retention prunes oldest (default 20). |
| Analysis tools | Non-AI: in-process syntax-check lint (token_get_all full-parse β no php -l/CLI subprocess), structure outline, metrics. AI: explain / refactor / docblocks / find-bugs (routed through DeepSeek on flash). |
| Settings β | A settings panel for an alternate working folder and alternate API-key path (relative or absolute), plus default model, thinking on/off + reasoning effort, DeepSeek timeout, editor font/tab-size/word-wrap, auto-backup-on-save, and the agentic-reading/PEEK knobs. Stored in dspe_settings.json (never web-served, kept outside working_folder/ so a folder switch never loses it); path changes prompt a reload. |
| Agentic reading π | When you ask the AI about (or to edit) a file, it automatically reads the files that file depends on β following include/require and resolving symbols (functions/classes/constants used here but defined elsewhere) via the project map. Bounded by file/byte/depth budgets (configurable); over-budget files degrade to a summary. Each answer shows a "read N related files" badge listing exactly what was pulled in. Deterministic β no extra LLM round-trips. |
| PEEK project map πΊ | A compact structural map of working_folder/ (symbols, signatures, namespaces, dependency edges) the AI is given so it understands your codebase without reading every file. Extracted with token_get_all(), cached at working_folder/.g023_peek.json and rebuilt incrementally (only changed files re-scan); browse it in the πΊ panel. |
| Security | Strict 'self' CSP, CSRF on every state-changing POST, hardened sessions, security headers, single safe_resolve() path gate, key never reaches the browser. dspe_settings.json is denied to the web alongside K.dat. |
dsphpedit/
βββ index.php Front-end shell (CSP, CSRF meta, vendored asset includes)
βββ config.php Paths, model policy, limits, settings resolution, self-creating state
βββ router.php Front controller for `php -S` (denies secrets/state)
βββ .htaccess Apache hardening (denies K.dat, dspe_settings.json, dotfiles; security headers)
βββ K.dat YOUR DeepSeek API key (git-ignored; never web-served)
βββ K.dat.example Placeholder you copy to K.dat
βββ dspe_settings.json operator settings (never web-served; outside working_folder/; auto-created on first save)
βββ lib/
β βββ ds4.php Canonical DeepSeek connector (ds4_chat / llm_get)
β βββ paths.php safe_resolve() β the ONE gate for all file I/O
β βββ security.php session bootstrap, CSRF, security headers, api_guard()
β βββ settings.php settings schema, validation, save, path checks
β βββ codemap.php PEEK map builder (symbols + dependency edges, cached)
β βββ context.php agentic reading (follows includes + symbol refs)
β βββ response.php JSON envelope helpers
βββ api/
β βββ files.php list / read / write / create / rename / delete / mkdir
β βββ preview.php server-side PHP execution (the headline feature)
β βββ ai_chat.php explain / full / edit modes (+ agentic context)
β βββ complete.php AI inline code completion (fill-in-the-middle)
β βββ settings.php get / save / reset operator settings
β βββ peek.php project map: render / structured / symbols / deps
β βββ upload.php finfo + GD re-encode + thumbnail
β βββ media.php media browse + thumbnail/raw serving
β βββ history.php conversation history
β βββ backup.php create / list / restore / delete (Zip-Slip-safe)
βββ ai_tools/assist.php programmatic AI tools (explain/refactor/docblocks/bugs)
βββ tools/
β βββ analyze.php non-AI lint / outline / metrics
β βββ selfcheck.php environment self-check
β βββ test_features.php settings / PEEK / agentic-reading suite (36 assertions)
β βββ test_paths.php traversal test suite
βββ assets/vendor/ Ace (BSD-3) + jQuery β all local, no CDN
βββ docs/PRD.md product requirements / spec of record
βββ working_folder/ YOUR project under edit (the sandbox boundary)
βββ welcome.php sample file (preview this first)
βββ uploads/ media (non-executable, .htaccess)
βββ g023_backups/ ZIP snapshots (auto-created)
βββ .g023_peek.json cached PEEK map (hidden, per-working-folder)
βββ g023_history.json conversation history (auto-created)
Boundary rule: every file read / write / upload / preview passes through
safe_resolve(), confining it to working_folder/.
- Endpoint:
https://api.deepseek.com/chat/completions(OpenAI-compatible). Bearer auth; key trimmed. - The connector returns
['reasoning', 'response', 'meta' => [id, model, finish_reason, usage, tool_calls?]]. reasoningcomes frommessage.reasoning_content(populated only when Thinking is enabled viathinking: {type: enabled}).- Default model
deepseek-v4-flash;deepseek-v4-prois opt-in. Legacydeepseek-chat/deepseek-reasonerare not targeted. - Code completion sends
thinking: {type: disabled}. flash reasons by default even when the param is omitted, and that reasoning adds latency and is counted againstmax_tokensβ often consuming the whole budget and returning an empty completion (finish_reason=length). Disabling thinking makes completions fast (~1s) and non-truncated. (The chat assistant leaves Thinking user-controllable.) - Code completion is FIM-with-dedup. The prompt sends up to 6000 chars of prefix and 4000 chars of suffix, instructing the model that the code after the cursor already exists and must not be rewritten. Because chat models still re-emit closers and restate just-typed tokens, the server trims the completion against the real prefix (
dspe_trim_prefix_overlap) and the full untruncated suffix (dspe_trim_suffix_overlap) before returning it β single-char overlaps are only trimmed when structural (punctuation / closers / whitespace) to avoid eating a coincidental identifier letter.
Every third-party asset (the Ace editor and jQuery) is downloaded into
assets/vendor/ and served locally. There are no external script tags, no
CDN calls, and no telemetry. Combined with the strict 'self' CSP, the browser
talks only to your own server. Third-party licenses are reproduced in
LICENSE and alongside the vendored code.
- AI says "no K.dat key": copy
K.dat.exampleβK.datand paste yoursk-...key. Editing/preview work without it. - Preview is blank / errors: PHP fatals are shown in the preview pane; check the diagnostics banner. Preview runs with a 15s timeout and a memory cap.
- "Write failed" on save/upload/backup: make
working_folder/writable by the web-server user. - Backups fail: ensure the
zipextension is loaded (php tools/selfcheck.php).
MIT Β© g023. See LICENSE.
Bundles Ace (BSD-3-Clause) and jQuery (MIT), vendored under assets/vendor/.
Built for builders. Drop a project in, edit, ask, preview. That's the whole loop.
β If this is useful, star it on GitHub.





