Howto:Store PBX CDRs on a Synology NAS locally using HTTP (Post)

From innovaphone wiki
Jump to navigation Jump to search

Applies To

This information applies to:

  • innovaphone PBX with CDR generation
  • innovaphone CDR1 interface
  • Synology NAS with DSM 7
  • Synology Web Station
  • PHP 8.2 or similar


More Information

This Howto explains how to store innovaphone PBX Call Detail Records (CDRs) on a Synology NAS.

The PBX sends the CDR data using HTTP POST to a small PHP receiver running on Synology Web Station.

The receiver stores multiple CDR entries inside the same log file.

When the current log file reaches the configured maximum size, a new log file is created automatically.

innovaphone PBX
      |
      | HTTP POST
      v
Synology Web Station
      |
      | receiver.php
      v
/web/cdr/logs/
      |
      +-- cdr_2026-09-17_12-30-00.log
      +-- cdr_2026-09-17_14-15-22.log
      +-- ...

Problem Details

The innovaphone PBX can generate CDR information for completed calls.

If the CDR information should be stored on an external Synology NAS, a small HTTP receiver can be used.

The PBX sends every CDR to the receiver.

The receiver:

  • receives the CDR using HTTP POST
  • adds the CDR to the current log file
  • creates a new file when the configured maximum size is reached
  • uses the date and time in the log filename

This avoids creating one file for every individual CDR.

System Requirements

The following components are required:

  • innovaphone PBX
  • CDR generation enabled
  • Synology NAS
  • Synology Web Station
  • PHP 8.2 or similar
  • network connectivity between the PBX and the Synology NAS

In this Howto the following example values are used:

Synology IP: 192.168.10.50
HTTP Port: 49173
Receiver: /receiver.php

These are only example values.

Replace 192.168.10.50 with the actual IP address of the Synology NAS.

The port can also be changed. It is recommended to use a high dedicated port instead of a common HTTP port.

Installation

Install Web Station and PHP

Open the Synology Package Center.

Install:

  • Web Station
  • PHP 8.2

After installation, open Web Station.

Create the CDR folders

Open Synology File Station.

Inside the web shared folder create:

/web/cdr/
/web/cdr/logs/

The folder structure should look like:

web
└── cdr
    ├── receiver.php
    └── logs

Configure permissions

The PHP web server must have permission to create and modify files inside the logs folder.

Open:

File Station
/web/cdr/logs
Properties
Permission

The Synology system user http must have Read & Write permission.

Apply the permission to:

This folder, sub-folders and files

synology_cdr_http_permissions.png/

If the http user has only Read permission, the PHP receiver can receive the request but cannot save the CDR.

The receiver may return:

500 Internal Server Error
Could not save CDR

Create receiver.php

Create a php file and place it in:

/web/cdr/receiver.php

Insert the following code:

<?php

/*
 * innovaphone CDR receiver for Synology
 *
 * What this script does:
 * 1. Receives a CDR sent by the PBX with HTTP POST.
 * 2. Saves the received CDR inside a log file.
 * 3. Keeps adding new CDRs to the same file.
 * 4. When the file becomes too large, it creates a new log file.
 */

$logDir = __DIR__ . "/logs";

/*
 * Maximum size of one log file.
 * 1024 * 1024 = 1 MB.
 *
 * Example for 10 MB:
 * $maxSize = 10 * 1024 * 1024;
 */
$maxSize = 1024 * 1024;

/*
 * This small file remembers which CDR log file is currently active.
 */
$stateFile = $logDir . "/current.txt";

/*
 * This file prevents two CDRs from being written
 * at exactly the same time.
 */
$lockFile = $logDir . "/.cdr.lock";

/*
 * Read the CDR data sent by the innovaphone PBX.
 */
$data = file_get_contents("php://input");

/*
 * Stop if no CDR data was received.
 */
if (empty($data)) {
    http_response_code(400);
    echo "No CDR data received";
    exit;
}

/*
 * Lock the storage while a CDR is being written.
 */
$lock = fopen($lockFile, "c");

if (!$lock || !flock($lock, LOCK_EX)) {
    http_response_code(500);
    echo "Could not lock CDR storage";
    exit;
}

/*
 * Read the name of the current log file.
 */
$currentName = "";

if (file_exists($stateFile)) {
    $currentName = trim(file_get_contents($stateFile));
}

/*
 * Build the full path of the current log file.
 */
$currentFile = $currentName !== ""
    ? $logDir . "/" . $currentName
    : "";

/*
 * Create a new log file when:
 * - no active file exists
 * - the active file was deleted
 * - the maximum file size would be exceeded
 */
if (
    $currentFile === "" ||
    !file_exists($currentFile) ||
    filesize($currentFile) + strlen($data) > $maxSize
) {

    /*
     * Create the filename using the current date and time.
     *
     * Example:
     * cdr_2026-09-17_12-30-00.log
     */
    $currentName = "cdr_" . date("Y-m-d_H-i-s") . ".log";
    $currentFile = $logDir . "/" . $currentName;

    /*
     * Add a unique value if the filename already exists.
     */
    if (file_exists($currentFile)) {
        $currentName =
            "cdr_" .
            date("Y-m-d_H-i-s") .
            "_" .
            uniqid() .
            ".log";

        $currentFile = $logDir . "/" . $currentName;
    }

    /*
     * Remember which log file is currently active.
     */
    file_put_contents($stateFile, $currentName);
}

/*
 * Add the new CDR to the end of the current log file.
 * Existing CDRs are not overwritten.
 */
$result = file_put_contents(
    $currentFile,
    $data . PHP_EOL,
    FILE_APPEND
);

/*
 * Release the lock.
 */
flock($lock, LOCK_UN);
fclose($lock);

/*
 * Return an error if the CDR could not be saved.
 */
if ($result === false) {
    http_response_code(500);
    echo "Could not save CDR";
    exit;
}

/*
 * Confirm that the CDR was successfully received and saved.
 */
http_response_code(200);
echo "OK";

?>

Example log files:

cdr_2026-09-17_12-30-00.log
cdr_2026-09-17_14-15-22.log

The default maximum file size is 1 MB.

Configuration

Create the PHP Web Service

Open:

Web Station
Web Service
Create

Create a PHP web service.

Example:

Name: receiver_cdr
PHP: PHP 8.2
Document root: /web/cdr

Save the configuration.

The service status should show Normal.

synology_cdr_web_service.png/

Create the Web Portal

Open:

Web Station
Web Portal
Create

Select the previously created CDR Web Service.

Configure:

Portal type: Port-based
HTTP: Enabled
Port: 49173

A high dedicated port is used in this example instead of a common HTTP port.

synology_cdr_web_portal.png/

The receiver URL will look similar to:

http://192.168.10.50:49173/receiver.php

Replace the IP address and, if required, the port with the values used in the actual installation.

Test the PHP receiver

Before configuring the PBX, test the receiver manually.

From Windows Command Prompt:

curl.exe -i -X POST -H "Content-Type: text/xml" --data-binary "<cdr><test>Hello</test></cdr>" "http://192.168.10.50:49173/receiver.php"

The expected answer is:

HTTP/1.1 200 OK

OK
synology_cdr_curl_test.png/

Check:

/web/cdr/logs/

A log file should have been created.

Enable CDR generation

Open:

PBX
General

Enable:

Generate CDRs

Configure CDR1

Open:

Gateway
CDR1

Configure:

Type: HTTP
Address: 192.168.10.50
Port: 49173
Method: POST
Path: /receiver.php

Replace the example IP address with the actual Synology IP address.

innovaphone_cdr1_synology_http.png/

Save the configuration.

The PBX must be able to reach:

<SYNOLOGY_IP>:<CDR_PORT>

For example:

192.168.10.50:49173

Test with a real call

Make a short call through the PBX:

Call
Answer
Hang up

Then check:

/web/cdr/logs/

The current log file should contain the CDR information generated by the PBX.

synology_cdr_logs.png/

Change the maximum log file size

The default maximum size is 1 MB.

You will see at first a file named "cdr_current.xml" once it reaches the limit set, it will save the cdr acumulated, and then it will keep on saving cdrs on "cdr_current.xml".

If you want to increase the maximum size go inside receiver.php:

$maxSize = 1024 * 1024;

For 10 MB:

$maxSize = 10 * 1024 * 1024;

Old log files are not deleted automatically.

Known Problems

HTTP is not encrypted

The setup described in this Howto uses HTTP.

The CDR information is therefore transmitted without encryption.

This configuration should only be used on a trusted internal network.

No authentication

The PHP receiver does not require a username or password.

A high dedicated port such as 49173 makes the service less obvious than using a common web port, but it must not be considered a security mechanism.

If possible, configure the Synology firewall so that the CDR port can only be accessed from the IP address of the innovaphone PBX.

Log files are not deleted automatically

The receiver creates new files when the configured maximum size is reached.

Old files remain on the NAS.

Storage usage should therefore be monitored.

HTTP 500 - Could not save CDR

Check:

/web/cdr/logs/

The Synology system user http must have Read & Write permission.