FOR PHP DEVELOPERS

Xdebug cannot run in production.
This can.

You know the shape of it. Something is slow on production, you cannot reproduce it locally, and the profiler you own is the one you are not allowed to turn on there. So you sprinkle microtime(), read the slow query log, and guess.

PHPRay records every PHP request where the problem actually happens: wall time, CPU, memory, every SQL query as a fingerprint, every outbound HTTP call, errors and N+1 patterns. It is a C extension plus a single Go binary. No agent with root, no SaaS account required, and the core is Apache-2.0.

# one line, then look at what is happening right now
curl -fsSL https://phpray.dev/install.sh -o phpray-install.sh
less phpray-install.sh          # it asks for root; read it first
sudo bash phpray-install.sh && phpray top

See a real report → Console on live traffic

The report is a real result from a production shop with the site name stripped. Nothing to install, no account, no e-mail address.

Why the tools you have do not fit

ToolWhere it stops
Xdebug profilerSuperb locally and for step debugging. In production the overhead is not acceptable and you get a cachegrind file per request, not a history you can search a day later.
New Relic, Blackfire, TidewaysReal products that solve this — if someone installs the agent and pays per host. On shared hosting you cannot install it at all, and on a small VPS the price is out of proportion to the app.
Slow query logTells you a query was slow. Not which request ran it, what else that request did, or which plugin or library issued it.
microtime() in codeWorks, and you have to guess the right place first — which is the thing you are trying to find out.

What you get instead

Every request, not a sample

Sampling agents keep statistics between samples. PHPRay writes one record per request, so the checkout that failed at 03:00 is still there at 09:00 — with its queries, its outbound calls and the error that ended it.

No root, no agent

If you can edit your own php.ini — and on most shared hosting, cPanel, Plesk and CloudLinux you can — you can load it yourself. Nothing leaves the PHP process unless you configure it to.

Overhead measured, not promised

On a WordPress page rendering in 48 ms the request-recording layer could not be separated from the baseline across five interleaved rounds. The per-plugin breakdown costs about 4% — and the same at any sample rate, because the observer is either installed or it is not.

What the answer looks like

Plugin list with time, share and impact: woocommerce 132 ms and 33.7% — high impact; wordfence 95 ms; elementor 51 ms

From a real WooCommerce store, 39,995 requests over one week — the whole finding, not a teaser:

  • urgent Requests are failing. 1,089 responses with a 5xx status, with the failing paths listed — each one a visitor who saw an error instead of a cart.
  • worth a look The queries that cost the most. The wp_options autoload query — 3.6 s in total over the window. Not the slowest per call, the most expensive overall, because it runs on every request.
  • for reference Where the time goes, component by component. wordfence 97 ms per request, woocommerce 82 ms, elementor 81 ms, the theme 42 ms.

SQL is stored as fingerprints with the literals stripped — WHERE email = ?. Request bodies, cookies and sessions are never touched.

Where it stops — so you do not find out later

  • It is not a line-level profiler. You get per-component attribution, not a flame graph of every function call. For that, Xdebug locally is still the right tool.
  • No step debugging. Different job.
  • The WordPress plugin (pure PHP, no extension) sees less than the extension: not the time before WordPress boots, and not requests that die before shutdown.
  • Cloud is optional. The local collector, the dashboard and phpray top are free and unlimited; you only pay if you want several servers in one console with longer history.

Look at your own traffic

Install locally in one line — open source, Apache-2.0, no account. Or take a free cloud account: one site, 10,000 traces a day, 7 days of history, no card.

Install it locally Create a free account

WordPress, and no shell at all?

The plugin does the same job in pure PHP 7.4+, GPLv2 — no extension, no daemon, no server access. Upload it under Plugins → Add New → Upload Plugin, paste the server key from the console, and the data flows.

Download the WordPress plugin (0.1.3, 34 kB)

Differences from the extension are in the documentation.