Isaac Chan · Site teardown ps.ps Preservation mirror Oct 2026

A portrait-photography blog on Palestine's country code

ps.ps is not a product, a scam, or a Photoshop tool. It is a Chinese-language photography blog: 27 short tutorial posts, a Z-BlogPHP install last updated in 2024, and a six-character domain that only exists because .ps happens to look like PS. This page is the whole thing — every page and every asset mirrored file-for-file — plus what the infrastructure around it does and does not reveal.

Pages mirrored
53 HTML files
Assets
84 css · js · img · font
Total size
10.6 MB, 9.8 of them photos
Posts
28 + about page
Median post
496 Chinese characters
Third-party requests
0 no ads, no analytics
The pun is the whole point

.ps is the ccTLD for Palestine, run by PNINA. Register ps.ps and you own a domain that reads as “PS” — Photoshop — with a dot in the middle. The site is a photography blog, so the name is doing exactly one job: being a six-character joke that a photographer can type.

01 · What is actually on the site

The masthead reads 凤翎公子 — 专注人像摄影 (“Fengling Gongzi — focused on portrait photography”). The author name is the same, and the keywords list the real editorial plan: 摄影基础 (photography basics), 人像摄影 (portraits), 摄影后期 (post-processing), 摄影器材 (gear), 手机摄影 (phone photography), 化妆技巧 (makeup), 主题妆造 (themed styling).

CategoryURLPostsWhat it covers
摄影?cate=120Exposure, ISO, shutter, metering, composition, light, depth of field
人像?cate=27Poses, 三庭五眼 facial proportions, 古风 / 复古法式 / 日系 / 欧美 styling shoots
妆造?cate=41A ten-step everyday makeup routine
关于?id=31About page

The posts are short and instructional, not a portfolio: the median post is 496 Chinese characters, the longest is about 765, and the shape is always the same — a numbered list of steps with the reasoning attached. “化妆步骤” (makeup steps) is literally ten ✅-prefixed steps, “相机五大档位” is five camera modes, “九种摄影构图” is nine compositions. Photography-as-recipe.

Dates run 2025-07-22 → 2026-09-06, and the distribution is the story: 24 of the 28 posts land in February 2026, 16 of them on a single day (2026-02-03), then one post in June and one in September. That is not a publishing rhythm; that is a content dump. Two IDs in the sequence (id=2, id=21) and two categories (cate=3, cate=5) return 404 at the origin — deleted or never published, and Z-BlogPHP happily renumbered around the holes.

版权声明: 内容均源于网络分享整理,如有侵权请及时联系删除。 — “Copyright notice: the content is compiled from material shared online; if it infringes, contact us and we will delete it.”

That single line is the most informative sentence on the site. This is aggregated content — the ten-step makeup routine is not the author's own shoot, and the photo credits belong to whoever took them. It also explains the volume: 16 photography explainers on one calendar day, all in the same numbered-steps template.

02 · The stack, read off the page

LayerWhat it isEvidence
CMSZ-BlogPHP 1.7.4/zb_system/ scripts, zbpConfig, ?id= routing
ThemeTztCard, build dated 2024-02-27zb_users/theme/TztCard/, ?2024-02-27 cache-bust
JSjQuery 2.2.4, viewer.min.js lightbox, jquery.qrcodescript tags in <head>
FontsIconfont (32 KB ttf)style/font/iconfont.ttf
Servernginx, no X-Powered-Byresponse headers
TLSCertum DV TLS G2 R39 CA (Asseco Data Systems, PL), valid to 2027-03-28openssl s_client
TransportHTTP → HTTPS 301, Strict-Transport-Security: max-age=31536000curl -I

Two small choices worth noting. There is no login form rendered and no comment UI in the templates — a blog with the social surface switched off, which is why there is nothing on the site for a visitor to break. And the PHP version is deliberately not advertised (no X-Powered-By), even though the CMS version is still exposed in the asset paths.

03 · Where it is hosted — and what that can and cannot tell you

This is the part where a “check the location” answer usually goes wrong, so here is the full evidence chain rather than a flag on a map.

ps.ps A record ──▶ 103.145.191.84 │ ├─ APNIC inetnum 103.145.190.0 – 103.145.191.255 │ netname SYNT-CN · holder Shanghai Yunchun Network Technology Co., Ltd. · country CN ├─ RADB route 103.145.190.0/23 origin AS55933 │ changed by [email protected] — “Customer Route” ├─ ipinfo.io ──▶ Tung Chung, Hong Kong · Cloudie Limited └─ NS eudora / cotton.dnspod.net ──▶ Tencent DNSPod

Those answers disagree, and both are correct: the IP block is allocated to a Shanghai company and announced through a Hong Kong transit provider (Cloudie, AS55933). Geolocation APIs report the network operator's facility, not the owner. Country-level is usually right; city-level is a rack number.

What this does not tell you: where the person lives, or who they are. An IP identifies the network the traffic lands on. For a site with no CDN, that is at least a real, single origin — which is more than can be said for anything behind Cloudflare (see the a1d2.org teardown for that failure mode).

04 · Is it safe?

What the checks found

  • No login, no forms except a search box that posts server-side
  • No third-party requests — not one ad, tracker, font CDN or analytics call
  • No downloads, no redirects: unknown paths return a plain nginx 404
  • URLhaus host lookup: no malware or abuse entry
  • HSTS on, HTTPS enforced with a 301

What would still stop me

  • Z-BlogPHP 1.7.4 is an old branch — never hand it a password or an account
  • Content is copied from elsewhere; the photos are not the author's
  • Search posts to a PHP endpoint on a CMS I would not trust with input
  • No sitemap.xml, no date/author metadata worth trusting

Reading this site is harmless. Logging into it would not be — and luckily there is nothing to log into.

05 · The mirror

Every page reachable from the homepage was fetched with a plain HTTP client and stored under a deterministic path, so the site works with no server, no PHP and no network. 53 pages, 84 assets, 10.6 MB — of which 9.8 MB is imagery: the article photographs plus the theme's generated thumbnails, which is where most of the weight sits.

Origin URLMirror pathCount
https://ps.ps/index.html1
/?id=Np/N.html31
/?cate=N, ?cate=N&page=Mcate/N.html, cate/N-M.html7
/?page=Npage/N.html6
/?date=YYYY-MMdate/YYYY-MM.html8
/zb_users/…, /zb_system/…same path, relative84

What was changed, exhaustively: the five rewrites below, and nothing else. Every other byte — every article, every image, every stylesheet, every script — is what the server sent.

  • Query-string routes → the file paths in the table above (a static host cannot route on ?id=)
  • Root-absolute asset URLs → paths relative to each file's depth, so the site works in a subfolder
  • c_html_js_add.php → c_html_js_add.js (served as JavaScript, not downloaded as PHP), with bloghost and ajaxurl blanked so the mirror can never POST to the live blog
  • The search form's action → # with onsubmit="return false"; search is server-side and cannot exist in a mirror
  • feed.php → feed.xml, so the RSS link still opens as XML

What still works in the mirror

  • Navigation: all 53 pages, pagination, categories, date archives
  • Lightbox image viewer (viewer.js), QR code dialog
  • The RSS feed, as a 50 KB XML file
  • Chinese text, fonts, and the icon font

What cannot

  • Search (server-side PHP)
  • Comments and login (not rendered at all)
  • Live view counters, if the theme ever had them

Fidelity check: each page's origin bytes were re-fetched and hashed at build time, and the MIRROR.json in the folder records URL → path → sha256 for all 137 files — 83 byte-identical, 54 differing only inside URL attributes, 0 unexplained. One caveat, measured over the wire: the host injects one line into every HTML page it serves (a Cloudflare Web Analytics <script>), so the archived file is byte-identical to the origin while the copy served from this portfolio is not. The difference is exactly one script tag at the end of <head>.

06 · What the mirror does not cover

The two deleted IDs and two deleted categories are 404 at the origin, so they are 404 here. There is no sitemap to prove the post list is complete — completeness is defined as “everything linked from the homepage and its pagination”, which is 53 pages. Category ?cate=1 runs to four pages and ?cate=2 to two; both were followed to the end. This is a snapshot taken on 2026-10-21: if the blog posts again, the mirror will not know.