Frontend URL replacement exhausts PHP memory on large responses
维护者通常 1 天内回复
@girishpanchal30 已经在做这个了。
开始于 2026年10月19日。
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 52/100
- Issue 类型
- 缺陷
- 描述清晰度
- 基本清楚
- 活跃度
- 活跃
- 领域
- frontend, performance
调研方向
从 inc/manager.php 开始,重点查看 process_template_redirect_content()、replace_content()、extract_urls_from_content()、normalize_urls() 和 do_url_replacement()。运行 tests/test-replacer.php,并检查其中现有的替换用例,然后再使用 128 MB 限制和大量不同的 URL 重现前端输出缓冲区工作流。完成的标准是,大响应路径不再因内存耗尽而终止,并且存在相关的回归覆盖。
由索引模型根据 Issue 内容生成。
描述
Summary
Optimole can exhaust the PHP memory limit while rewriting URLs in a frontend response that contains a large number of distinct eligible URLs. Expected behavior: frontend output optimization completes without terminating the request under supported site content. Actual behavior: the request terminates with an allowed-memory-size fatal error during URL replacement. Impact: affected visitors receive a failed frontend response instead of the rendered page.
Customer context
- Product / area: Optimole WordPress plugin, frontend output URL replacement
- Version: 4.2.10
- Environment: WordPress 7.1; PHP 7.4.33 and PHP 8.1.2-1ubuntu2.25; 128 MB PHP memory limit in reported crashes
- Integration / third party: Not provided
- Reported error / symptom:
Allowed memory size of 134217728 bytes exhausted (tried to allocate 90112 bytes) - Impact: 2 occurrences across 2 distinct production sites between 2026-08-21 and 2026-08-25.
Reproduction notes
- Use a frontend request eligible for Optimole output replacement.
- Render a sufficiently large response containing many distinct URLs matching Optimole's image or asset extraction rules.
- Run with a 128 MB PHP memory limit.
- Observed in production: the request can terminate at URL replacement with
Allowed memory size of 134217728 bytes exhausted.
A local runtime reproduction was not performed; exact content size and URL cardinality are unknown.
Diagnosis
Conclusion
Production telemetry records a frontend fatal at inc/manager.php:784. The inspected code buffers the full frontend response, extracts all distinct matching URLs, then applies a full-string preg_replace() once for each URL. This creates a direct memory-exhaustion path for sufficiently large content or high unique-URL cardinality. The reported fatal is in Optimole product code, not Themeisle SDK code.
Where this likely occurs
inc/manager.php—Optml_Manager::process_template_redirect_content()lines 793-817 starts an output buffer for eligible frontend requests and passes the full response toreplace_content().inc/manager.php—Optml_Manager::replace_content()lines 441-533 invokesprocess_urls_from_content()at lines 525-529 after other whole-content processing.inc/manager.php—Optml_Manager::extract_urls_from_content()andOptml_Manager::normalize_urls()lines 703-737 collect matching URLs and deduplicate them, with no observed bound on input size or number of unique URLs.inc/manager.php—Optml_Manager::do_url_replacement()lines 748-785 loops over each extracted URL and assigns a completepreg_replace()result back to$htmlat line 784, matching the production crash location.v4.2.10is release commit060fd3fe(2026-07-15). The inspectedv4.2.9..v4.2.10diff contains no change toinc/manager.php; blame attributes the replacement loop tob7f67fd7(2019-12-14). Available history does not establish a regression in 4.2.10.
Engineering notes
The failure surface is the non-partial frontend output-buffer workflow when URL processing reaches do_url_replacement(). The peak memory requirement can grow with both the buffered response size and the count of distinct image or, when CDN processing is active, asset URLs. Two production reports on different PHP versions reached the same fatal location under a 128 MB memory limit. The exact page size, URL count, active Optimole settings, and other plugins on those sites are unavailable.
Test coverage status
tests/test-replacer.php covers functional replacement through test_optimization_url() lines 217-226, test_assets_url() lines 323-358, test_style_replacement() lines 372-379, and test_elementor_data() lines 482-505. These tests assert transformed output for representative content but do not cover large buffered responses, high unique-URL cardinality, peak memory, or the frontend output-buffer hook. No relevant resource-bound coverage was found during inspection.
What to verify or explore next
- May be worth reproducing with the frontend output-buffer workflow, a constrained 128 MB PHP memory limit, and progressively larger HTML containing distinct eligible image and asset URLs.
- If reproducible, checking peak memory for
replace_content()anddo_url_replacement()separately may distinguish extraction cost from repeated replacement cost. - May be worth confirming behavior with CDN asset processing enabled and disabled, since
extract_urls_from_content()expands the eligible extensions when that setting is active.
Unknowns / follow-up
- The telemetry report has no structured stack trace beyond the fatal location.
- The specific response size, number of extracted URLs, and per-site Optimole configuration were not captured.
- No earlier working release boundary is available from the incident evidence.
Confidence
Confidence: 91/100
Behavior inventory: 1. A frontend Optimole URL-replacement request can exhaust PHP memory. Production telemetry pinpoints the fatal at the per-URL replacement loop, and repository inspection confirms that a complete buffered response is repeatedly processed without a content-size or URL-cardinality bound. The path is product code, not the Themeisle SDK.
Crash telemetry
| Occurrences | 2 |
| Distinct sites | 2 |
| First seen | 2026-08-21 04:36 UTC |
| Last seen | 2026-08-25 09:18 UTC |
| Crash location | product:inc/manager.php:784 |
| Request context | frontend |
| Inside Themeisle SDK | no |
| Product versions | 4.2.10 |
| WP versions | 7.1 |
| PHP versions | 7.4.33, 8.1.2-1ubuntu2.25 |
| SDK versions | 3.3.58, 3.3.59 |
Source: automated crash report — optimole-wp, fingerprint e16d0f7a1b6dbfc263cf3fb43ab3af81
Generated by bug-report-triage (ID: bug-report-triage_6a8e81425e50f1.08531822)
- 主要语言
- PHP
- 星标
- 74
- 派生
- 14
- 平均合并
- 1 天 22 小时
- 30 天内合并 PR
- 29
环境准备
- 提供 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
Codeinwp/optimole-wp 的其他 Issue
-
Page profiler endpoint fatals on PHP 8 when the request has no `b` (background selectors) field可能已有人在做 @girishpanchal30 于 1 天前认领。 未关闭bug
难度 2/5 1-3 小时 新手友好度 88/100
Codeinwp/optimole-wp#1204 · 4 条评论 · 已指派 1 人 ·
维护者通常 1 天内回复
-
Background image with a gradient is not lazy-loaded on WordPress 7.1 (Quote, Pullquote, Verse, Post Content, Accordion)可能已有人在做 @girishpanchal30 于 1 天前认领。 未关闭bug
难度 2/5 1-3 小时 新手友好度 78/100
Codeinwp/optimole-wp#1203 · 3 条评论 · 已指派 1 人 ·
维护者通常 1 天内回复
-
Page profiler never treats the detected LCP image as LCP, so it gets no fetchpriority="high" (stored ID is a string, compared with === to an int)可能已有人在做 @girishpanchal30 于 1 天前认领。 未关闭bug
难度 2/5 1-3 小时 新手友好度 88/100
Codeinwp/optimole-wp#1202 · 3 条评论 · 已指派 1 人 ·
维护者通常 1 天内回复
-
Account sign-up fatals when the Optimole API returns an empty or non-JSON response可能已有人在做 @girishpanchal30 于 1 天前认领。 未关闭bug
难度 2/5 1-3 小时 新手友好度 85/100
Codeinwp/optimole-wp#1200 · 3 条评论 · 已指派 1 人 ·
维护者通常 1 天内回复
-
Renaming an image leaves the old URL in comments and term descriptions, with "Unknown column 'ID'" database errors可能已有人在做 @girishpanchal30 于 1 天前认领。 未关闭bug
难度 2/5 1-3 小时 新手友好度 74/100
Codeinwp/optimole-wp#1199 · 3 条评论 · 已指派 1 人 ·
维护者通常 1 天内回复
查看 Codeinwp/optimole-wp 的全部 Issue
相似的 Issue
-
C-CDA export: allergy concern act code, policy activity translation and empty id/@extension fail conformance可能已有人在做 @doctorman 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 70/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 70/100
-
help wanted
难度 1/5 1 小时以内 新手友好度 82/100
-
scope:testing status:unconfirmed
难度 2/5 1-3 小时 新手友好度 65/100
wp-cli/wp-cli-tests#389 · 1 条评论 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 62/100
the-benchmarker/web-frameworks#10153 ·
维护者通常 1 天内回复