Modern websites require dynamic interactions without full page reloads. Our solution is AJAX controller development on top of 1C-Bitrix D7. These controllers replace legacy ajax.php scripts, bringing transparency, security, and testability. Our team has 10 years of experience in Bitrix development, with over 50 successful projects migrating to D7. Debugging time savings reach 50%, and support costs decrease by 40%. For example, a typical migration reduces AJAX-related incidents from 10 to 2 per month. Clients save on average $3,000 per year on debugging costs.
What are the benefits of using AJAX controllers?
When developing an online store, tasks often arise: loading products without reloading, catalog filtering, dynamic cart. Each such endpoint requires authorization, CSRF protection, and a standard response format. Without D7 controllers, each developer writes their own crutch, leading to code duplication and security holes. D7 controllers provide a unified pattern: inherit \Bitrix\Main\Engine\Controller, describe an action, attach filters — and you get a ready-made endpoint with checks. This speeds up development by 40% and reduces bugs by 30%.
Problems solved by AJAX controllers
A custom ajax.php is a concentration of risks: no centralized CSRF check, no standard error handling, code scattered across files. The D7 controller solves all this out of the box. It ensures data security through built-in authorization and CSRF protection. Example of a simple controller for displaying a product list:
namespace MyVendor\Catalog\Controller; use Bitrix\Main\Engine\Controller; use Bitrix\Main\Engine\ActionFilter; class Product extends Controller { public function configureActions(): array { return [ 'getList' => [ 'prefilters' => [ new ActionFilter\Authentication(), // authorization check new ActionFilter\Csrf(), // CSRF token ], ], ]; } public function getListAction(int $sectionId, int $page = 1): array { // Return an array — Bitrix will automatically wrap it in {"status":"success","data":{...}} return [ 'items' => $this->loadProducts($sectionId, $page), 'total' => $this->countProducts($sectionId), ]; } } The framework automatically wraps the return value in a JSON envelope {"status": "success", "data": {...}} or {"status": "error", "errors": [...]} when an exception is thrown.
How to implement custom filters?
The controller supports a chain of filters before and after action execution. This is analogous to middleware in Laravel. Built-in filters work on average 2 times faster than custom checks because they execute at the kernel level. We guarantee that every controller undergoes security checks according to Bitrix standards.
Standard prefilters:
-
ActionFilter\Authentication— requires authorization -
ActionFilter\Csrf— checks CSRF token (bitrix_sessid) -
ActionFilter\HttpMethod— restricts methods (GET/POST) -
ActionFilter\Scope— restricts context (web only, REST only, CLI only)
Custom filters for enhanced security
Suppose you need to restrict access to products only for users with a specific role. Create a filter class extending Base and inject it into the prefilters chain. This is more flexible than checking permissions in each action separately.
class ResourceAccessFilter extends \Bitrix\Main\Engine\ActionFilter\Base { public function onBeforeAction(Event $event): ?EventResult { $action = $event->getParameter('action'); $sectionId = $action->getController()->getRequest()->getPost('sectionId'); if (!SectionAccessChecker::canRead((int)$sectionId)) { $this->addError(new \Bitrix\Main\Error('Access denied', 403)); return new EventResult(EventResult::ERROR, null, null, $this); } return null; } } Controller registration process
The controller is registered in the module's routing file routes.php:
\Bitrix\Main\Routing\RoutingConfigurator::registerRoutes(function($routes) { $routes->post('/api/catalog/product/get-list/', 'MyVendor\Catalog\Controller\Product::getListAction'); }); An alternative method is through the standard component mechanism: the controller is called via /bitrix/services/main/ajax.php?action=myvendor:catalog.product.getList.
Handling files and complex data
The controller automatically deserializes incoming data. For file uploads — via $this->getRequest()->getFile('image'), the result is an object \Bitrix\Main\Web\Upload\UploadedFile with type and size validation methods.
For pagination, the built-in object \Bitrix\Main\Engine\Response\DataType\Page is used:
public function getListAction(int $page): \Bitrix\Main\Engine\Response\DataType\Page { $pageSize = 20; $items = ProductTable::getList([ 'limit' => $pageSize, 'offset' => ($page - 1) * $pageSize, ])->fetchAll(); return new \Bitrix\Main\Engine\Response\DataType\Page('items', $items, fn() => ProductTable::getCount()); } Benefits of migrating from ajax.php
Migrating to D7 controllers reduces debugging time by 50%. Instead of scattered scripts, you get a single class with tests. One of our clients reduced AJAX-related incidents from 10 to 2 per month after migration. We help perform migration gradually, starting with the most loaded endpoints. CSRF protection is automatically handled. PHPUnit tests ensure reliability. On average, migration pays for itself in 6 months, saving $3,000 per year.
Testing controllers without HTTP
Testing AJAX controllers without HTTP does not require a web server. Follow these steps:
- Create a mock of the
Requestobject. - Instantiate the controller with the mock.
- Call
run()method. - Assert the response.
This allows writing unit tests for each action. We use this approach on all projects and guarantee test coverage. Learn more about PHPUnit.
Step-by-step migration guide
- Identify all custom
ajax.phpendpoints. - Create D7 controllers with corresponding actions.
- Register routes and apply filters.
- Update frontend calls to use new endpoints.
- Run existing tests and perform regression testing.
- Remove old
ajax.phpfiles.
What's included in turnkey development
| Component | Description |
|---|---|
| Design | Definition of endpoints, data schemas, filters |
| Implementation | Coding controllers with custom filters |
| Integration | Connecting to existing components and 1C |
| Testing | PHPUnit, load testing |
| Documentation | OpenAPI specification, readme for developers |
| Migration | Phased migration from legacy ajax.php |
| Support | Consulting and refinements after delivery |
Development timelines and cost
| Scale | Scope | Timeline | Cost |
|---|---|---|---|
| Basic | 5–10 endpoints + standard filters | 1–2 weeks | $1,000 |
| Medium | + custom filters + file upload + rate limiting | 3–4 weeks | $2,500 |
| Extended | + versioning + OpenAPI documentation + tests | 5–7 weeks | $5,000 |
Contact us for a consultation — we will assess your project and offer the optimal solution. Our catalog API Bitrix D7 controllers are designed for high-load online stores. We also provide controller authorization Bitrix integration out of the box. Order AJAX controller development and get rid of legacy scripts.







