A modern, fluent PHP package for managing robots.txt rules with type safety and great developer experience.
- PHP 8.4 or higher
- Code coverage driver
You can install the package via composer:
composer require fkrzski/robots-txtThe RobotsTxt class provides a fluent interface for creating and managing robots.txt rules with type safety and immutability.
Creates a new instance of the RobotsTxt class.
$robots = new RobotsTxt();Output:
// Empty output - no rules defined yet
Adds an Allow rule for the specified path. The path must:
- Start with a forward slash (/)
- Not contain query parameters
- Not contain fragments
- Not be empty
$robots = new RobotsTxt();
$robots->allow('/public');Output:
User-agent: *
Allow: /public
Adds a Disallow rule for the specified path. Has the same path requirements as allow().
$robots = new RobotsTxt();
$robots->disallow('/private');Output:
User-agent: *
Disallow: /private
Sets the crawl delay in seconds. The delay value must be non-negative.
$robots = new RobotsTxt();
$robots->crawlDelay(10);Output:
User-agent: *
Crawl-delay: 10
Adds a Sitemap URL. The URL must:
- Be a valid URL
- Use HTTP or HTTPS protocol
- Have an .xml extension
$robots = new RobotsTxt();
$robots->sitemap('https://example.com/sitemap.xml');Output:
Sitemap: https://example.com/sitemap.xml
A convenience method for quickly blocking access to the entire site. When $disallow is true (default):
- Clears all existing rules in the current context (global or user-agent specific)
- Adds a single "Disallow: /*" rule
- Preserves sitemap entries and rules for other user agents
// Block everything globally
$robots = new RobotsTxt();
$robots
->allow('/public') // This will be cleared
->disallow('/admin') // This will be cleared
->disallowAll(); // Only Disallow: /* remainsOutput:
User-agent: *
Disallow: /*
Block access only for specific crawler:
$robots = new RobotsTxt();
$robots
->disallow('/admin') // Global rule - keeps
->userAgent(CrawlerEnum::GOOGLE)
->allow('/public') // Google rule - cleared
->disallow('/private') // Google rule - cleared
->disallowAll() // Only Disallow: /* for Google
->userAgent(CrawlerEnum::BING)
->disallow('/secret'); // Bing rule - keepsOutput:
User-agent: *
Disallow: /admin
User-agent: Googlebot
Disallow: /*
User-agent: Bingbot
Disallow: /secret
When $disallow is false, the method does nothing.
Sets the context for subsequent rules to apply to a specific crawler.
$robots = new RobotsTxt();
$robots->userAgent(CrawlerEnum::GOOGLE);Output:
User-agent: Googlebot
You can chain multiple rules together:
$robots = new RobotsTxt();
$robots
->disallow('/admin')
->allow('/public')
->crawlDelay(5);Output:
User-agent: *
Disallow: /admin
Allow: /public
Crawl-delay: 5
You can set rules for specific crawlers:
$robots = new RobotsTxt();
$robots
->userAgent(CrawlerEnum::GOOGLE)
->disallow('/private')
->allow('/public')
->crawlDelay(10);Output:
User-agent: Googlebot
Disallow: /private
Allow: /public
Crawl-delay: 10
You can define rules for multiple crawlers:
$robots = new RobotsTxt();
$robots
->userAgent(CrawlerEnum::GOOGLE)
->disallow('/google-private')
->userAgent(CrawlerEnum::BING)
->disallow('/bing-private');Output:
User-agent: Googlebot
Disallow: /google-private
User-agent: Bingbot
Disallow: /bing-private
The forUserAgent() method provides a closure-based syntax for grouping crawler-specific rules:
$robots = new RobotsTxt();
$robots->forUserAgent(CrawlerEnum::GOOGLE, function (RobotsTxt $robots): void {
$robots
->disallow('/private')
->allow('/public')
->crawlDelay(10);
});Output:
User-agent: Googlebot
Disallow: /private
Allow: /public
Crawl-delay: 10
Combining global rules, multiple crawlers, and sitemaps:
$robots = new RobotsTxt();
$robots
->disallow('/admin') // Global rule
->sitemap('https://example.com/sitemap1.xml')
->forUserAgent(CrawlerEnum::GOOGLE, function (RobotsTxt $robots): void {
$robots
->disallow('/google-private')
->allow('/public/*');
})
->forUserAgent(CrawlerEnum::BING, function (RobotsTxt $robots): void {
$robots
->disallow('/bing-private')
->crawlDelay(5);
})
->sitemap('https://example.com/sitemap2.xml');Output:
User-agent: *
Disallow: /admin
User-agent: Googlebot
Disallow: /google-private
Allow: /public/*
User-agent: Bingbot
Disallow: /bing-private
Crawl-delay: 5
Sitemap: https://example.com/sitemap1.xml
Sitemap: https://example.com/sitemap2.xml
The library supports wildcards in paths:
$robots = new RobotsTxt();
$robots
->disallow('/*.php') // Block all PHP files
->allow('/public/*') // Allow all under public
->disallow('/private/$'); // Exact match for /private/Output:
User-agent: *
Disallow: /*.php
Allow: /public/*
Disallow: /private/$
Saves the robots.txt content to a file. If no path is provided, saves to robots.txt in the project root directory.
$robots = new RobotsTxt();
$robots
->disallow('/admin')
->allow('/public');
// Save to default location (project root)
$robots->toFile();
// Save to custom location
$robots->toFile('/var/www/html/robots.txt');The method will throw a RuntimeException if:
- The target directory doesn't exist or isn't writable
- The existing robots.txt file isn't writable
Returns true if the file was successfully written.
- Start with Global Rules: Define global rules before crawler-specific rules for better organization.
- Group Related Rules: Use the
forUserAgent()method to group rules for the same crawler. - Use Wildcards Carefully: Be precise with wildcard patterns to avoid unintended matches.
- Order Matters: More specific rules should come before more general ones.
- Validate Paths: Always ensure paths start with a forward slash and don't contain query parameters or fragments.
The class will throw InvalidArgumentException in the following cases:
- Path doesn't start with forward slash
- Path contains query parameters or fragments
- Path is empty
- Sitemap URL is invalid or not HTTP/HTTPS
- Sitemap URL doesn't end with .xml
- Crawl delay is negative
These validations ensure that the generated robots.txt file is always valid and follows the standard format.
The project includes several command groups for testing and code quality:
# Run profanity checks
composer test:profanity
# Run static analysis with PHPStan
composer analyse
# Format code with Laravel Pint
composer lint
# Check code formatting (without fixing)
composer test:lint
# Run automated refactoring with Rector
composer refactor
# Check refactor suggestions (dry-run)
composer test:refactor
# Check type coverage (100% required)
composer test:type-coverage# Check PHP syntax
composer test:syntax
# Run unit tests with coverage
composer test:unit
# Run mutation testing
composer test:unit:mutation# Run all tests and quality checks
composer testWe welcome contributions! Please see our Contributing Guide for details on:
- Setting up the development environment
- Running tests
- Submitting pull requests
- Code style guidelines
- Reporting issues
- Fork this repository
- Clone your fork:
git clone https://github.com/yourusername/php-package-skeleton.git - Install dependencies:
composer install - Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes and run tests:
composer test - Submit a pull request
This project is open-sourced software licensed under the MIT License.
PHP Package Skeleton was created by Filip KrzyΕΌanowski.
Special thanks to the amazing PHP community and the maintainers of:
Happy coding! π
