# Landing page developer guidelines
This document contains technical tips and rules for developers who create landing pages for work in the tracker-sandbox environment.
# Using curl in PHP
 To prevent scripts from being interrupted unexpectedly, it is important to consider the execution time limits:
- The maximum time for a PHP script to run is set via the - TRACKER_LANDING_PAGES_TIMEOUTvariable (in seconds).
- If a - curlrequest runs longer than this time, it is forcibly interrupted.
- Make sure to specify the timeout via - CURLOPT_TIMEOUT— the value is 1 second less than- TRACKER_LANDING_PAGES_TIMEOUT.
Example of setting the timeout:
$systemTimeout = getenv('TRACKER_LANDING_PAGES_TIMEOUT') ?: 10;
$curlTimeout = max(1, $systemTimeout - 1);
$ch = curl_init('https://example.com/api');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, $curlTimeout);
$response = curl_exec($ch);
if (curl_errno($ch)) {
echo 'Curl error: ' . curl_error($ch);
} else {
echo 'Response: ' . $response;
}
curl_close($ch);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Timeouts in
curlare especially important when working with slow external APIs or when chainingcurlcalls inside a landing page.
# Using Guest Redis
The tracker-sandbox container has a built-in Redis service intended only for temporary data storage, debugging, and testing. Use it if caching in memory, or files is not suitable.
# Features
- Redis is only available locally, inside the container. 
- Connection is made using authorization data, which the system provides through environment variables. 
- Store data in Redis only temporarily — it can be deleted or overwritten. 
Timeouts in curl are especially important when working with slow external APIs or when using a chain of curl calls inside a landing page.
# Example of connecting to PHP 8.3 using phpredis
 <?php
$redis = new Redis();
try {
$redisHost = getenv('GUEST_REDIS_HOST');
$redisPort = getenv('GUEST_REDIS_PORT');
$redisUser = getenv('GUEST_REDIS_KEITARO_USER');
$redisPassword = getenv('GUEST_REDIS_KEITARO_PASSWORD');
$redis->connect($redisHost, $redisPort);
if (!$redis->auth([$redisUser, $redisPassword])) {
throw new RedisException("Redis authorization error: invalid username or password");
}
$redis->set('example_key', 'hello world');
$value = $redis->get('example_key');
echo "Received value: " . $value . PHP_EOL;
} catch (RedisException $e) {
echo "Redis error: " . $e->getMessage() . PHP_EOL;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Discard file_put_contents in favor of Redis
 Using the file system (file_put_contents(), fopen(), fwrite(), etc.) is not recommended for the following reasons:
- Files may conflict with parallel requests. 
- Temporary files are not guaranteed to be saved after the request is completed. 
- File system may be cleaned or reinitialized between container restarts. 
- Potential issues with permissions and - open_basedirrestrictions.
It is recommended to use guest Redis as a safe and fast storage for temporary data.
# Example: replacing file_put_contents
 Produced:
$data = json_encode(['foo' => 'bar']);
file_put_contents('/tmp/my-cache.json', $data);
2
Now:
$redis->set('my-cache-key', json_encode(['foo' => 'bar']));
# Example: replacing file_get_contents
 Produced:
$data = file_get_contents('/tmp/my-cache.json');
$array = json_decode($data, true);
2
Now:
$data = $redis->get('my-cache-key');
$array = json_decode($data, true);
2
Use logical keys, possibly with prefixes (landing:lead_data:123), to avoid overlaps and simplify debugging.
If data needs to be stored for a limited time, use setex():
$redis->setex('temp:token', 60, 'abc123'); // expires in 60 seconds
