Skip to main content

Overview

The Seguridad system requires specific PHP configuration, web server setup, and security settings to function properly. This guide covers all necessary configuration steps.

PHP Requirements

Version Requirements

Minimum Version

PHP 7.0 or higher

Recommended Version

PHP 7.4 or PHP 8.0+

Required PHP Extensions

pgsql
required
PostgreSQL database connectivity
# Install on Ubuntu/Debian
sudo apt install php-pgsql

# Install on CentOS/RHEL
sudo yum install php-pgsql
pdo_pgsql
recommended
PDO PostgreSQL driver (for future improvements)
sudo apt install php-pdo-pgsql
mbstring
required
Multibyte string handling (for character encoding)
sudo apt install php-mbstring
session
required
Session management (typically built-in)Verify: php -m | grep session

Verify Extensions

verify_extensions.php
<?php
$required = ['pgsql', 'session', 'mbstring'];
$recommended = ['pdo_pgsql', 'gd', 'json'];

echo "<h2>Required Extensions</h2>";
foreach ($required as $ext) {
    $status = extension_loaded($ext) ? '✓' : '✗';
    echo "$status $ext<br>";
}

echo "<h2>Recommended Extensions</h2>";
foreach ($recommended as $ext) {
    $status = extension_loaded($ext) ? '✓' : '✗';
    echo "$status $ext<br>";
}
?>

PHP Configuration (php.ini)

Critical Settings

; Error handling
error_reporting = E_ALL & ~E_DEPRECATED & ~E_STRICT
display_errors = Off
display_startup_errors = Off
log_errors = On
error_log = /var/log/php/error.log

; Session configuration
session.save_handler = files
session.save_path = "/var/lib/php/sessions"
session.use_cookies = 1
session.use_only_cookies = 1
session.cookie_httponly = 1
session.cookie_secure = 0  ; Set to 1 if using HTTPS
session.cookie_samesite = "Lax"
session.gc_maxlifetime = 3600  ; 1 hour
session.gc_probability = 1
session.gc_divisor = 100

; File uploads
upload_max_filesize = 20M
post_max_size = 25M
file_uploads = On

; Memory and execution
memory_limit = 256M
max_execution_time = 300
max_input_time = 300

; PostgreSQL
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off
pgsql.max_persistent = -1
pgsql.max_links = -1

; Character encoding
default_charset = "UTF-8"
mbstring.language = Spanish
mbstring.internal_encoding = UTF-8

; Date and timezone
date.timezone = America/Argentina/Buenos_Aires
Never use development settings in production! Always disable display_errors and enable proper logging.

Apply Configuration Changes

1

Edit php.ini

Locate your php.ini file:
php --ini | grep "Loaded Configuration File"
Common locations:
  • Ubuntu/Debian: /etc/php/7.4/apache2/php.ini
  • CentOS/RHEL: /etc/php.ini
  • Windows: C:\php\php.ini
2

Make Changes

Edit the file with your preferred editor:
sudo nano /etc/php/7.4/apache2/php.ini
3

Restart Web Server

# Apache
sudo systemctl restart apache2

# Nginx + PHP-FPM
sudo systemctl restart php7.4-fpm

# Windows IIS
iisreset
4

Verify Changes

Create phpinfo.php:
<?php phpinfo(); ?>
Access via browser and search for your settings

Web Server Configuration

Apache 2.4 Configuration

<VirtualHost *:80>
    ServerName seguridad.local
    DocumentRoot /var/www/seguridad
    
    <Directory /var/www/seguridad>
        Options -Indexes +FollowSymLinks
        AllowOverride All
        Require all granted
        
        # PHP settings
        php_value upload_max_filesize 20M
        php_value post_max_size 25M
        php_value max_execution_time 300
        php_flag display_errors Off
    </Directory>
    
    # Logs
    ErrorLog ${APACHE_LOG_DIR}/seguridad_error.log
    CustomLog ${APACHE_LOG_DIR}/seguridad_access.log combined
    
    # Security headers
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set X-XSS-Protection "1; mode=block"
</VirtualHost>

Enable Site

# Enable required modules
sudo a2enmod rewrite
sudo a2enmod headers

# Enable site
sudo a2ensite seguridad.conf

# Test configuration
sudo apache2ctl configtest

# Restart Apache
sudo systemctl restart apache2

Session Management

Session Configuration

The system uses PHP sessions extensively for authentication and state management:
<?php
@session_start();

// Set session variables on login
$_SESSION["ultimoAcceso"] = date("Y-n-j H:i:s");
$_SESSION["autentificado"] = "SI";
$_SESSION["_usr"] = $username;
$_SESSION["_pass"] = $password;  // Store hashed instead!
$_SESSION["_categoria"] = $permission_code;
?>

Session Security Improvements

Prevents session fixation attacks:
// After successful authentication
session_regenerate_id(true);
$_SESSION["_usr"] = $username;
$_SESSION["_categoria"] = $permission;
// Current (INSECURE)
$_SESSION["_pass"] = $password;

// Improved (don't store password)
$_SESSION["_usr"] = $username;
$_SESSION["_authenticated"] = true;
$_SESSION["_login_time"] = time();
// Generate token
if (empty($_SESSION['csrf_token'])) {
    $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}

// Include in forms
echo '<input type="hidden" name="csrf_token" 
      value="' . $_SESSION['csrf_token'] . '">';

// Validate on submission
if ($_POST['csrf_token'] !== $_SESSION['csrf_token']) {
    die('CSRF token validation failed');
}

Security Configuration

Error Suppression Issues

The codebase uses @ error suppression extensively:
@session_start();
@$res = pg_query($sql);
@$row = pg_fetch_row($res);
This hides critical errors and makes debugging difficult.
Recommendation: Remove @ operators and implement proper error handling:
// Instead of:
@$result = pg_query($sql);

// Use:
$result = pg_query($sql);
if (!$result) {
    error_log("Database error: " . pg_last_error());
    die("An error occurred. Please contact support.");
}

SQL Injection Prevention

// VULNERABLE to SQL injection
$sql = "SELECT * FROM usuario 
        WHERE usd='$user' AND pwd='$pass'";
$res = pg_exec($sql);

File Permissions

1

Set Ownership

# Set web server as owner
sudo chown -R www-data:www-data /var/www/seguridad
2

Set Directory Permissions

# Directories: 755 (rwxr-xr-x)
find /var/www/seguridad -type d -exec chmod 755 {} \;
3

Set File Permissions

# PHP files: 644 (rw-r--r--)
find /var/www/seguridad -type f -name "*.php" \
    -exec chmod 644 {} \;
4

Protect Configuration Files

# Config files: 600 (rw-------)
chmod 600 /var/www/seguridad/miconexion.php
chmod 600 /var/www/seguridad/*/miconexion.php
5

Writable Directories

# Upload directories: 775 (rwxrwxr-x)
mkdir -p /var/www/seguridad/uploads
chmod 775 /var/www/seguridad/uploads
chown www-data:www-data /var/www/seguridad/uploads

Logging Configuration

PHP Error Logging

# Create log directory
sudo mkdir -p /var/log/seguridad
sudo chown www-data:www-data /var/log/seguridad
sudo chmod 755 /var/log/seguridad
<?php
// Set custom error log
ini_set('error_log', '/var/log/seguridad/php_errors.log');

// Custom error handler
function customErrorHandler($errno, $errstr, $errfile, $errline) {
    $message = date('[Y-m-d H:i:s] ') . 
               "Error [$errno]: $errstr in $errfile on line $errline\n";
    error_log($message, 3, '/var/log/seguridad/app_errors.log');
    
    // Display user-friendly message
    if (ini_get('display_errors') == '0') {
        echo "An error occurred. Please contact support.";
    }
}

set_error_handler('customErrorHandler');
?>

Log Rotation

/etc/logrotate.d/seguridad
/var/log/seguridad/*.log {
    daily
    rotate 30
    compress
    delaycompress
    missingok
    notifempty
    create 0644 www-data www-data
    sharedscripts
    postrotate
        systemctl reload apache2 > /dev/null 2>&1 || true
    endscript
}

Performance Optimization

php.ini
[opcache]
opcache.enable=1
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
opcache.fast_shutdown=1
// Use persistent connections
$conn = pg_pconnect(
    "host=$host port=$port dbname=$dbname " .
    "user=$user password=$pass"
);
Monitor connection pool to avoid exhaustion
php.ini
output_buffering = 4096
In code
<?php
ob_start();
// ... page content ...
ob_end_flush();
?>

Environment-Specific Configuration

config_dev.php
<?php
// Development environment
error_reporting(E_ALL);
ini_set('display_errors', 1);
ini_set('log_errors', 1);

// Database
define('DB_HOST', 'localhost');
define('DB_PORT', '5434');
define('DB_NAME', 'seguridad_dev');
define('DB_USER', 'postgres');
define('DB_PASS', 'dev_password');

// Session (short timeout for testing)
ini_set('session.gc_maxlifetime', 600);
?>

Health Check

Create a system health check script:
health_check.php
<?php
header('Content-Type: application/json');

$health = [
    'status' => 'ok',
    'checks' => []
];

// Check PHP version
$health['checks']['php_version'] = [
    'status' => version_compare(PHP_VERSION, '7.0', '>=') ? 'ok' : 'fail',
    'version' => PHP_VERSION
];

// Check extensions
$required_extensions = ['pgsql', 'session', 'mbstring'];
foreach ($required_extensions as $ext) {
    $health['checks']['extension_' . $ext] = [
        'status' => extension_loaded($ext) ? 'ok' : 'fail'
    ];
}

// Check database connection
try {
    $conn = pg_connect("host=localhost port=5434 dbname=seguridad_db user=postgres");
    $health['checks']['database'] = [
        'status' => $conn ? 'ok' : 'fail'
    ];
    if ($conn) pg_close($conn);
} catch (Exception $e) {
    $health['checks']['database'] = ['status' => 'fail', 'error' => $e->getMessage()];
}

// Check session directory
$session_path = session_save_path();
$health['checks']['session_directory'] = [
    'status' => is_writable($session_path) ? 'ok' : 'fail',
    'path' => $session_path
];

// Overall status
foreach ($health['checks'] as $check) {
    if ($check['status'] === 'fail') {
        $health['status'] = 'fail';
        break;
    }
}

echo json_encode($health, JSON_PRETTY_PRINT);
?>

Database Setup

PostgreSQL configuration

User Management

Session-based authentication

Permissions

Access control system

Regional Units

Multi-unit architecture

Build docs developers (and LLMs) love