Fill PHP templates with realistic placeholder content, vary the length of an article, or show an image only some of the time. Reload the page to see how your layout handles a different combination.
This is a generated snapshot of the PHP demo. Run Dummy locally to get fresh random content on every request.
Getting Started
Requirements
Use PHP 8.3 or newer with the GD extension enabled. Composer 2 is needed for package installation. The Laravel integration supports Laravel 12 and 13. Dummy needs no database, Docker setup, or native PHP session.
To run the demo locally, use the following command from the Dummy directory, then open localhost:8000/demo.php.
Terminal
php -S localhost:8000
Install with Composer
From your application directory, install Dummy as a development dependency. Composer loads dummy(), dumb_luck(), and dumb_question() automatically.
After installing with Composer, run this command from your Laravel application's root directory:
Terminal
php artisan vendor:publish --tag=dummy-assets
Laravel discovers Dummy's service provider automatically. The command publishes images, text pools, and ad templates to public/vendor/dummy/assets. Generated crops go into public/vendor/dummy/cache, which PHP creates automatically. The web server needs permission to create and write to that cache directory.
Create resources/views/dummy-demo.blade.php and use the helpers directly in the view:
dummy() prints its result. Use @php(...) for it rather than Blade's escaped {{ ... }} output. The 50% condition shows the image about half the time, and the loop produces between three and eight items.
Add a route to routes/web.php:
PHP
use Illuminate\Support\Facades\Route;
Route::view('/dummy-demo', 'dummy-demo');
Start Laravel with your application's normal development command, or run php artisan serve. Open localhost:8000/dummy-demo when using the default local port. Laravel serves the published assets and cached crops from its public directory.
Composer in a standalone PHP project
After the Composer installation above, put Dummy's assets under your public web root. For a project with a public directory, run:
Make sure PHP can create public/dummy/cache, or create it yourself and give the web server write access. Start the server from your application directory and open localhost:8000/demo.php:
Terminal
php -S localhost:8000 -t public
If your project serves files from another directory, adjust the include path and asset locations to match that web root. Generated lorem ipsum works without copying assets; named text pools, images, and ads need the published files.
Plain PHP without Composer
Copy the entire dummy directory into your public web root. Keep dummy.php, Runtime.php, Lorem.php, and the assets directory together.
Create a PHP template in that web root and include Dummy before calling its helpers:
Make dummy/cache writable by PHP. Dummy creates the directory if its parent is writable. Use php -S localhost:8000 from that web root, or your usual PHP development server, and open the template in your browser.
The image below demonstrates image cropping and caching. It uses a larger source image so it stays sharp on high-density displays.
Success. Images are rendering and the cache directory is writable.
Paths, cache & image settings
In Laravel, publish the configuration if you need different asset paths or a URL prefix:
Set custom paths before publishing assets. The URL must serve the matching asset and cache directories. If configuration is cached, run php artisan config:cache after changing it.
Outside Laravel, set $dummy_path, $dummy_assets_path, and $dummy_cache_path before rendering, as in the Composer example above. The include path is a filesystem path; $dummy_path is the public URL prefix. Inside a function, set these through $GLOBALS.
Optional image constants such as JPEG_QUALITY (default 90), MAX_WIDTH_PX (default 2048), and MAX_HEIGHT_PX (default 1536) must be set before loading Dummy. In Laravel or a Composer project, that means before loading vendor/autoload.php. Use a fresh cache directory when changing JPEG quality so existing crops are not reused.
Troubleshooting
If PHP cannot find Dummy, check the filesystem path in require_once. Use __DIR__ so it does not depend on the current working directory.
If images fail to load, confirm that the configured public URL points to the assets and cache directories, and that PHP can write to the cache.
If GD is missing, enable the GD extension for the PHP runtime serving the page. Your terminal and web server can use different PHP configurations.
Use standard <?php ... ?> tags. Old templates using <? ... ?> need PHP's short_open_tag setting; new examples do not.
Text pools and custom ad templates can contain executable PHP. Use trusted local files. Keep Dummy as a development dependency for prototyping and QA.
Dummy Assets
The ability to select, manipulate, and insert different assets into your front-end project is a key feature of Dummy. All of the assets available to Dummy live in a folder located at dummy/assets/. It's a good idea to poke around in here and see how things are structured. The simple syntax used to request different assets relates very much to the structure of this directory.
Dummy Text
Dummy makes it easy to insert random strings of Lorem Ipsum that correspond to commonly needed lengths and formats. For example, the following snippet of code will produce a random string of Lorem Ipsum approximately the length of a headline.
PHP + HTML
<?php dummy("text@headline") ?>
The exact result will be different every time you reload your document, but it should look something like this...
Nullam Quis Risus Eget Urna Mollis Ornare Vel Eu Leo
The following table is a catalog of Dummy's default assets, the snippet of code used to insert the asset, and a sample of actual output.
Objective
Dummy Code
Output
Headline
<?php dummy("text@headline") ?>
Curabitur Gravida, Lorem id Venenatis Sodales
Teaser
<?php dummy("text@teaser") ?>
Lorem ipsum dolor sit amet consectetuer adipiscing elit.
Short Teaser
<?php dummy("text@short-teaser") ?>
Pretium taciti sodales porta ut condimentum.
Long Teaser
<?php dummy("text@long-teaser") ?>
Fusce et risus nonummy neque euismod pretium. Donec dignissim ligula vitae ipsum. Maecenas a velit eu lectus blandit blandit.
Item
<?php dummy("text@item") ?>
Consectetur
Date
<?php dummy("text@date") ?>
October 18th, 2026
Time
<?php dummy("text@time") ?>
12:44 pm
Time ago (relative)
<?php dummy("text@time-ago") ?>
12 days ago
Author
<?php dummy("text@author") ?>
Romain Garceau
Username
<?php dummy("text@username") ?>
amppilot
City
<?php dummy("text@city") ?>
Florence
Paragraph
<?php dummy("text@paragraph") ?>
Nam vulputate convallis massa viverra tristique. Aenean aliquet egestas pulvinar. Phasellus ante orci, sollicitudin quis congue non, scelerisque vitae leo. Phasellus a tortor quis dolor pharetra convallis. Pellentesque et neque et libero rhoncus tempus in id libero. Integer enim enim, mollis ac tincidunt ut, luctus id justo. Integer in magna urna, eu blandit libero. Sed quis massa erat. Aenean eros sapien, volutpat sed sodales ac, aliquam a risus. Quisque cursus, magna quis semper imperdiet, arcu orci tempus nulla, consectetur tristique eros felis at arcu.
Hint: Inside of dummy/assets/text/ you'll find a directory full of flat text files. These are the basis for organizing different text formats used by Dummy. You can edit these or add your own as you like.
Lorem ipsum at any length
Keep using named text pools for headlines and other curated content, or generate fresh lorem ipsum by specifying a count. Use a single number for an exact length, or a range for a different length on each call.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Vestibulum id ligula porta felis euismod semper. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Fusce dapibus, tellus ac cursus commodo.
30–60 words
<?php dummy("text@words:30-60") ?>
Pellentesque ornare sem lacinia quam venenatis vestibulum. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Curabitur blandit tempus porttitor. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Pellentesque ornare sem lacinia quam venenatis vestibulum. Morbi.
5–9 words, title case
<?php dummy("text@words:5-9,title") ?>
Duis Aute Irure Dolor In Reprehenderit.
2–4 sentences
<?php dummy("text@sentences:2-4") ?>
Etiam porta sem malesuada magna mollis euismod. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vestibulum id ligula porta felis euismod semper.
2–3 paragraphs
<?php dummy("text@paragraphs:2-3") ?>
Donec ullamcorper nulla non metus auctor fringilla. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Maecenas faucibus mollis interdum. Curabitur blandit tempus porttitor. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi leo risus, porta ac consectetur ac, vestibulum at eros.
Donec ullamcorper nulla non metus auctor fringilla. Praesent commodo cursus magna, vel scelerisque nisl consectetur et. Maecenas faucibus mollis interdum. Nullam quis risus eget urna mollis ornare vel eu leo. Etiam porta sem malesuada magna mollis euismod.
Output is plain text. Add ,title to capitalize every word; omit it for normal sentence casing. Paragraphs are separated by blank lines; use your own markup or CSS to display those breaks. Zero returns no text. Ranges include both endpoints. Limits per call: 10,000 words, 1,000 sentences, or 100 paragraphs. No extra packages or asset publishing needed.
Dummy Images
Dummy makes it easy to crop and size placeholder images on the fly. It ships with a starter pack of high-quality, newsworthy, Creative Commons licensed images, but like other assets it's easy to edit or expand these according to the needs of your project.
The syntax for requesting an image is flexible. In a very basic example, you request an image with specific dimensions...
PHP + HTML
<img src="<?php dummy("image@480x320") ?>" />
...and the following is returned:
This example returns exactly 480×320 image pixels. At 480 CSS pixels wide, it is a 1× image; high-density screens benefit from a larger crop, as shown below.
You can specify exact pixel dimensions or just an aspect ratio. You can also combine these parameters. For example, you can choose to specify just the width together with an aspect ratio. Dummy will return the path to an image that conforms to both requirements.
PHP + HTML
<img src="<?php dummy("image@640x,16:9") ?>" />
Returns...
Use the returned image URL in your <img> element's src attribute.
Sharp images on high-density screens
Image dimensions are real pixels, not CSS display sizes. For a photo displayed at 640 pixels wide, request a larger crop and set its display width separately. The example below requests 1920×1080 pixels and displays them at 640×360, giving the browser three image pixels per CSS pixel.
The bundled image/retina folder contains 2048×1536 source photos. Some older landscape photos are only 1024–1150 pixels wide. A larger request cannot restore detail missing from the original.
JPEG crops are encoded at quality 90 by default. That adds some compression, but reducing the pixel dimensions is the main reason the earlier demo looked soft on a high-density screen. Supply a sufficiently large source and request enough pixels for the intended display size. Aspect-ratio-only commands such as image@16:9 crop at the source's available resolution.
The following table provides some clues as to how you can structure your image requests.
Objective
Dummy Code
Output
100px square Classic. Square.
<?php dummy("image@100x100") ?>
100px square (Part II) A rather pointless way of generating the same result as above. Proving a point here.
<?php dummy("image@100x,1:1") ?>
16:9 With a height of 200px. Pixel dimensions and aspect ratios must be separated with a comma.
<?php dummy("image@16:9,x200") ?>
16:9 (Part II) Same as above. It doesn't matter which order you specify ratio or pixel dimensions.
<?php dummy("image@x200,16:9") ?>
3:2 The Photographer's aspect! We'll ask for assets from a specific subdirectory of ‘dummy/assets/image/’ here to improve the odds of getting a suitable image.
<?php dummy("image/landscape@3:2") ?>
!Avatar Subdirectories of ‘dummy/assets/image/’ that begin with a ‘!’ are exempted from normal random (and recursive) selection. You have to target them specifically. This is good.
<?php dummy("image/!avatar@150x150") ?>
Note: When specifying dimensions, either as an exact pixel measurement or as an aspect ratio, describe the width first and height second (Width x Height).
The basic model for how Dummy selects image assets is semi-random and recursive. It begins looking for assets on the root level of "assets/image" and drills down, only ignoring sub-folders with names that begin with a ‘!’. Dummy also works in the background to track which image was most recently selected, in order to minimize the odds of inserting the same image in succession or in close proximity.
Dummy Ads
Inside of /dummy/assets/ad you'll find a host of folders representing many of the popular formats as defined by the IAB. The dummy code used to request and insert an ad follows the now familiar model.
PHP + HTML
<?php dummy("ad@120x90") ?>
Returns...
Note that a request for an ad returns a pre-formatted block of embed code containing an ad, as opposed to just the URL path to the ad (as is done with images). The reason for this is that we often need blocks of repetitious, ancillary markup to surround ad placements, as is the case with regard to advertising in the Adobe® Flash® format.
The default embed code for both standards compliant image based ads and ads in the Flash format can be found on the root level of /dummy/assets/ad in the form of two files — image.embed.php and flash.embed.php respectively. You can override the use of these defaults by placing an edited copy of one or both of these files in the folder of the format you wish to override.
The folders containing different formats are also used to specify their dimensions (WxH). Dummy parses these folder names and interprets them as variables, which in turn can be used to set the width and height values of ads as they are parsed into the embed code. If you don't feel it necessary to pass these values to your embed code, you're free to add new formats in folders and name them however you like — just remember to create a custom embed for these formats.
You may find it useful to enable or disable the insertion of Flash format ads under different testing scenarios. Set $flash_ads = true before rendering to include legacy Flash ads. The default is disabled, and current browsers do not support Flash.
Dumb Luck
The ability to insert randomly selected assets into a layout is great, but it's Dummy's simple logic for controlling probability and creating loop ranges that make it possible to flesh out highly variable, asset rich layouts with very little code. The basis for this logic is contained in a function called dumb_luck.
Controlling Probability
A basic building block of Dummy driven layouts, dumb_luck can be used to influence the probability that something will happen when the document is rendered. This helps answer the age old question, “What does this layout look like with or without X ?”, where X could be an image, a special announcement, or a block of JavaScript that triggers some other chain of events.
PHP + HTML
<?php if (dumb_luck("50%")): ?>
There is a 50/50 chance of this happening.
<?php endif ?>
Jazz up your dumb_luck logic with fallback or alternative outcomes using standard PHP if/else statement structure.
PHP + HTML
<?php if (dumb_luck("95%")): ?>
Pretty damn likely to happen.
<?php else: ?>
This is a lot less likely.
<?php endif ?>
You can also nest dumb_luck logic as needed, to test and explore more complex outcomes.
PHP + HTML
<?php if (dumb_luck("50%")): ?>
<?php if (dumb_luck("50%")): ?>
Heads
<?php else: ?>
Tails
<?php endif ?>
<?php else: ?>
<?php if (dumb_luck("33%")): ?>
Rock
<?php elseif (dumb_luck("33%")): ?>
Paper
<?php else: ?>
Scissors
<?php endif ?>
<?php endif ?>
For the record... Rock!
Creating Loop Ranges
Dumb Luck's loop range takes whatever content you place inside of it and loops it within a range of two numbers that you specify. Inside of the loop range above, a single request for a 35x35 pixel thumbnail.
Loop ranges make it possible to generate massive amounts of variable content very quickly. In the example above, there are two bits of Dummy code working together. A dumb_luck loop range of 50-100, and inside of that loop range, a single request for a 35x35 pixel thumbnail.
The thumbnail will be rendered no less than 50 times, and up to 100. The Dummy code used to achieve this is compact and human readable:
PHP + HTML
<?php while (dumb_luck("50-100")): ?>
<?php dummy("image@35x35") ?>
<?php endwhile ?>
Loop ranges are built on the same dumb_luck function used to control probability, only instead of passing in a % value we pass it a range of two numbers separated by a hyphen. These two values define the minimum and maximum number of times the loop should continue. In the example below, we ask for between 5 and 10 instances of a list item containing a headline.
Note that the PHP syntax used with dumb_luck requires “WHILE” in association with loop ranges.
The result is a simple UL containing between 5 and 10 list items:
Vel Scelerisque Nisl Consectetur Et
Nullam Id Dolor Id Nibh Ultricies Vehicula
Maecenas Faucibus Mollis Interdum
Fusce Dapibus, Tellus Ac Cursus Commodo
Donec Ullamcorper Nulla Non Metus Auctor Fringilla
Putting It All Together
Taking the same list used in the previous example, imagine we needed to see how it would look with some of the items linked some of the time. To achieve this we'll nest some probability logic inside of our loop range.
Though the exact number will change every time you reload the page, roughly half of the items in the following list will be wrapped in a link. It's a very basic example, but one that uses all the core features of Dummy.
When used together, asset generation, probability, and loop range logic can create highly variable layouts with very little effort in code. This makes it possible to quickly test how the change of an item, attribute or parameter in one place propagates on a range of different scales. It can provide new insights on the performance or design efficacy of your work at the earliest stages of a project, and every time you reload the page.
An example of a simple article 3 to 8 paragraphs in length, with optionally appearing intro text and related story elements.
Loop positions and request queries
Inside a loop, dumb_question("order:first"), dumb_question("order:last"), and dumb_question("order:inner") test the current position. dumb_luck("") prints the one-based item number.
dumb_question("url:mode=compact") tests a query parameter, and dumb_question("segment:1=news") tests the first URL path segment. Laravel uses its current request automatically. See paths, cache and image settings for configuration.
In the meantime, follow the project on GitHub. Your ideas and contributions toward improving the code are welcome.