Close Menu
    DevStackTipsDevStackTips
    • Home
    • News & Updates
      1. Tech & Work
      2. View All

      Error’d: Pickup Sticklers

      September 27, 2025

      From Prompt To Partner: Designing Your Custom AI Assistant

      September 27, 2025

      Microsoft unveils reimagined Marketplace for cloud solutions, AI apps, and more

      September 27, 2025

      Design Dialects: Breaking the Rules, Not the System

      September 27, 2025

      Building personal apps with open source and AI

      September 12, 2025

      What Can We Actually Do With corner-shape?

      September 12, 2025

      Craft, Clarity, and Care: The Story and Work of Mengchu Yao

      September 12, 2025

      Cailabs secures €57M to accelerate growth and industrial scale-up

      September 12, 2025
    • Development
      1. Algorithms & Data Structures
      2. Artificial Intelligence
      3. Back-End Development
      4. Databases
      5. Front-End Development
      6. Libraries & Frameworks
      7. Machine Learning
      8. Security
      9. Software Engineering
      10. Tools & IDEs
      11. Web Design
      12. Web Development
      13. Web Security
      14. Programming Languages
        • PHP
        • JavaScript
      Featured

      Using phpinfo() to Debug Common and Not-so-Common PHP Errors and Warnings

      September 28, 2025
      Recent

      Using phpinfo() to Debug Common and Not-so-Common PHP Errors and Warnings

      September 28, 2025

      Mastering PHP File Uploads: A Guide to php.ini Settings and Code Examples

      September 28, 2025

      The first browser with JavaScript landed 30 years ago

      September 27, 2025
    • Operating Systems
      1. Windows
      2. Linux
      3. macOS
      Featured
      Recent
    • Learning Resources
      • Books
      • Cheatsheets
      • Tutorials & Guides
    Home»Development»Mastering PHP File Uploads: A Guide to php.ini Settings and Code Examples

    Mastering PHP File Uploads: A Guide to php.ini Settings and Code Examples

    September 28, 2025Updated:September 28, 2025

    Mastering PHP File Uploads: A Guide to php.ini Settings and Code Examples

    PHP offers a powerful, yet sometimes intricate, set of directives in its php.ini file to manage everything from file size limits to temporary storage.

    This article will break down the essential php.ini settings related to file uploads, explain their purpose, and provide practical PHP code examples to demonstrate how to interact with these settings and process uploads effectively.


    1. file_uploads

    • Default Value: On
    • Value Type: Boolean (On/Off)
    • Description: This fundamental directive determines whether **HTTP file uploads** are permitted at all. If set to Off, all attempts to upload files via PHP scripts will fail, regardless of other settings.

    Why it matters:

    This is your master switch for uploads. If you’re building a system that doesn’t require file uploads, setting this to Off can be a small but effective security measure by explicitly disabling functionality.

    Code Example: Checking file_uploads in PHP

    You can check the current value of this setting within your PHP script, though remember that it cannot be changed at runtime.

    <?php
    
    $fileUploadsStatus = ini_get('file_uploads');
    
    if ($fileUploadsStatus == '1') { // ini_get returns '1' for On, '' for Off
    echo "File uploads are currently ENABLED on this server.<br>";
    } else {
    echo "File uploads are currently DISABLED on this server.<br>";
    }
    
    ?>

    2. upload_tmp_dir

    • Default Value: (empty string – uses system default)
    • Value Type: String (Path)
    • Description: Specifies the **temporary directory** used to store uploaded files before the script processes and moves them. If this directive is not set, PHP will use the system’s default temporary directory (e.g., /tmp on Linux, C:\Windows\Temp on Windows).

    Why it matters:

    • Performance: You might want to specify a high-performance disk or a dedicated partition for temporary uploads if your application handles a large volume of files.
    • Security: This directory **must be writable** by the web server user. It should also **not be publicly accessible** via the web. Files stored here are unvalidated and could potentially be malicious.

    Code Example: Discovering the Temporary Directory

    You can find out what temporary directory PHP is using:

    <?php
    
    $tempDir = ini_get('upload_tmp_dir');
    
    if (!empty($tempDir)) {
    echo "PHP is configured to use: " . htmlspecialchars($tempDir) . " for temporary uploads.<br>";
    } else {
    echo "PHP is using the system's default temporary directory (e.g., /tmp).<br>";
    echo "You can find the default path using sys_get_temp_dir(): " . sys_get_temp_dir() . "<br>";
    }
    
    // Example of checking if the directory is writable (best practice to ensure functionality)
    if (is_writable($tempDir ?: sys_get_temp_dir())) {
    echo "The temporary upload directory is writable.<br>";
    } else {
    echo "WARNING: The temporary upload directory is NOT writable! Uploads might fail.<br>";
    }
    
    ?>

    3. upload_max_filesize

    • Default Value: 2M
    • Value Type: Bytes (shorthand notation: K, M, G)
    • Description: The **maximum size for a single uploaded file**. If a user attempts to upload a file larger than this limit, PHP will reject it.

    Why it matters:

    This is your primary control for individual file sizes. Setting it too high can expose your server to large, resource-intensive uploads, while setting it too low can frustrate users. It’s crucial to balance user needs with server capacity.

    Code Example: Handling upload_max_filesize and Form Integration

    This example shows a basic HTML form and PHP script to handle an upload, including a client-side check (which is easily bypassed but good for UX) and server-side checks.

    index.html (or your form page):

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>File Upload Example</title>
    </head>
    <body>
    <h1>Upload a File</h1>
    <form action="upload.php" method="POST" enctype="multipart/form-data">
        <input type="hidden" name="MAX_FILE_SIZE" value="2097152" />
        <label for="userFile">Choose file (max 2MB):</label>
        <input type="file" name="userFile" id="userFile" /><br><br>
        <input type="submit" value="Upload File" />
    </form>
    
    <script>
        document.getElementById('userFile').addEventListener('change', function() {
            const maxFileSize = parseInt(document.querySelector('input[name="MAX_FILE_SIZE"]').value);
            if (this.files[0] && this.files[0].size > maxFileSize) {
                alert('File is too large! Max allowed is ' + (maxFileSize / (1024 * 1024)) + 'MB.');
                this.value = ''; // Clear the file input
            }
        });
    </script>
    </body>
    </html>

    upload.php:

    <?php
    
    // Retrieve PHP's configured upload_max_filesize for comparison
    $phpMaxUploadSize = parse_size(ini_get('upload_max_filesize'));
    
    // Helper function to convert PHP's shorthand notation to bytes
    function parse_size($size) {
    $unit = preg_replace('/[^bkmgtpezy]/i', '', $size); // Remove the non-unit characters from the size.
    $size = preg_replace('/[^0-9\.]/', '', $size); // Remove the non-numeric characters from the size.
    
    if ($unit) {
        // Find the position of the unit in the ordered string and multiply by the appropriate factor.
        return round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
    }
    
    return round($size);
    }
    
    if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    if (isset($_FILES['userFile']) && $_FILES['userFile']['error'] == UPLOAD_ERR_OK) {
        $file = $_FILES['userFile'];
    
        // Server-side check against PHP's actual limit
        if ($file['size'] > $phpMaxUploadSize) {
            echo "Error: The uploaded file exceeds the server's configured 'upload_max_filesize' of " . ini_get('upload_max_filesize') . ".<br>";
        } else {
            $targetDir = "uploads/";
            // Ensure target directory exists and is writable
            if (!is_dir($targetDir) && !mkdir($targetDir, 0755, true)) {
                die("Failed to create upload directory.");
            }
            if (!is_writable($targetDir)) {
                die("Upload directory is not writable.");
            }
    
            $targetFile = $targetDir . basename($file['name']);
    
            // Attempt to move the uploaded file from temp directory to its final destination
            if (move_uploaded_file($file['tmp_name'], $targetFile)) {
                echo "The file ". htmlspecialchars( basename( $file['name'])). " has been uploaded.<br>";
                echo "Size: " . round($file['size'] / 1024, 2) . " KB<br>";
            } else {
                echo "Sorry, there was an error uploading your file.<br>";
                echo "Error code: " . $file['error'] . "<br>";
            }
        }
    } else {
        // Handle various upload errors
        switch ($_FILES['userFile']['error']) {
            case UPLOAD_ERR_INI_SIZE:
                echo "Error: The uploaded file exceeds the 'upload_max_filesize' directive in php.ini.<br>";
                break;
            case UPLOAD_ERR_FORM_SIZE:
                echo "Error: The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.<br>";
                break;
            case UPLOAD_ERR_PARTIAL:
                echo "Error: The uploaded file was only partially uploaded.<br>";
                break;
            case UPLOAD_ERR_NO_FILE:
                echo "Error: No file was uploaded.<br>";
                break;
            case UPLOAD_ERR_NO_TMP_DIR:
                echo "Error: Missing a temporary folder for uploads.<br>";
                break;
            case UPLOAD_ERR_CANT_WRITE:
                echo "Error: Failed to write file to disk.<br>";
                break;
            case UPLOAD_ERR_EXTENSION:
                echo "Error: A PHP extension stopped the file upload.<br>";
                break;
            default:
                echo "Unknown upload error occurred.<br>";
                break;
        }
    }
    } else {
    echo "Please use the form to upload files.<br>";
    }
    
    ?>

    4. max_file_uploads

    • Default Value: 20
    • Value Type: Integer
    • Description: This directive sets the **maximum number of files** that can be uploaded in a single HTTP POST request. If a user tries to upload more files than this limit, any additional files beyond the limit will be silently ignored by PHP.

    Why it matters:

    Useful for preventing denial-of-service attacks where an attacker might try to overwhelm your server by uploading an excessive number of tiny files. It also helps manage the $_FILES array size.

    Code Example: Multiple File Uploads

    index.html (or your form page):

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <title>Multiple File Upload Example</title>
    </head>
    <body>
    <h1>Upload Multiple Files</h1>
    <p>Server allows max <span id="maxUploadsDisplay">...</span> files.</p>
    <form action="upload_multiple.php" method="POST" enctype="multipart/form-data">
        <label for="userFiles">Choose files (up to <span id="maxFilesLabel">20</span>):</label>
        <input type="file" name="userFiles[]" id="userFiles" multiple /><br><br>
        <input type="submit" value="Upload Files" />
    </form>
    
    <script>
        // This part needs to fetch the max_file_uploads limit from the server
        // A simple AJAX call could do this, or you could hardcode a known limit for client-side UX.
        // For demonstration, let's assume we fetch it via AJAX:
        fetch('get_php_settings.php?setting=max_file_uploads')
            .then(response => response.json())
            .then(data => {
                const maxUploads = parseInt(data.value);
                document.getElementById('maxUploadsDisplay').textContent = maxUploads;
                document.getElementById('maxFilesLabel').textContent = maxUploads;
    
                document.getElementById('userFiles').addEventListener('change', function() {
                    if (this.files.length > maxUploads) {
                        alert('You can only upload a maximum of ' + maxUploads + ' files at once.');
                        this.value = ''; // Clear the file input
                    }
                });
            })
            .catch(error => console.error('Error fetching max_file_uploads:', error));
    </script>
    </body>
    </html>

    get_php_settings.php (to support the client-side JavaScript):

    <?php
    header('Content-Type: application/json');
    
    if (isset($_GET['setting'])) {
    $setting = $_GET['setting'];
    
    echo json_encode(['setting' => $setting, 'value' => ini_get($setting)]);
    } else {
    echo json_encode(['error' => 'No setting specified.']);
    }
    ?>

    upload_multiple.php:

    <?php
    
    // Retrieve PHP's configured max_file_uploads
    $phpMaxFileUploads = (int)ini_get('max_file_uploads');
    
    if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    if (!empty($_FILES['userFiles']['name'][0])) { // Check if at least one file was selected
        $totalFiles = count($_FILES['userFiles']['name']);
    
        if ($totalFiles > $phpMaxFileUploads) {
            echo "Error: You attempted to upload " . $totalFiles . " files, but the server only allows a maximum of " . $phpMaxFileUploads . " files per request.<br>";
            echo "Only the first " . $phpMaxFileUploads . " files (if any) might have been processed.<br>";
        }
    
        $uploadedCount = 0;
        $targetDir = "uploads_multi/";
        if (!is_dir($targetDir) && !mkdir($targetDir, 0755, true)) {
            die("Failed to create multi-upload directory.");
        }
        if (!is_writable($targetDir)) {
            die("Multi-upload directory is not writable.");
        }
    
        foreach ($_FILES['userFiles']['name'] as $key => $name) {
            // Only process if the upload was successful for this specific file
            if ($_FILES['userFiles']['error'][$key] == UPLOAD_ERR_OK) {
                $tmp_name = $_FILES['userFiles']['tmp_name'][$key];
                $targetFile = $targetDir . basename($name);
    
                if (move_uploaded_file($tmp_name, $targetFile)) {
                    echo "File " . htmlspecialchars($name) . " uploaded successfully.<br>";
                    $uploadedCount++;
                } else {
                    echo "Error uploading " . htmlspecialchars($name) . ".<br>";
                }
            } else {
                // Optionally handle individual file errors
                // echo "Error with file " . htmlspecialchars($name) . ": " . $_FILES['userFiles']['error'][$key] . "<br>";
            }
        }
    
        echo "<hr>Total " . $uploadedCount . " files successfully uploaded.<br>";
    } else {
        echo "No files were selected for upload.<br>";
    }
    } else {
    echo "Please use the form to upload files.<br>";
    }
    
    ?>

    5. post_max_size

    • Default Value: 8M
    • Value Type: Bytes (shorthand notation: K, M, G)
    • Description: This defines the **maximum size of all POST data** that PHP will process in a single request. This is critical because it includes not only all uploaded files (their combined size) but also all other form fields (text inputs, hidden fields, etc.). If the total POST data exceeds this limit, PHP will silently discard the entire POST body, resulting in empty $_POST and $_FILES superglobals.

    Why it matters:

    This setting often catches developers off guard. If your $_POST and $_FILES arrays are mysteriously empty after a large submission, **post_max_size is usually the culprit**. It must always be equal to or greater than upload_max_filesize.

    Code Example: Detecting post_max_size Issues

    There’s no direct PHP error constant for exceeding post_max_size like there is for upload_max_filesize. You detect it by checking if $_POST and $_FILES are empty when you expect data.

    upload.php (modified to detect post_max_size issue):

    <?php
    // Helper function from previous example
    function parse_size($size) {
    $unit = preg_replace('/[^bkmgtpezy]/i', '', $size);
    $size = preg_replace('/[^0-9\.]/', '', $size);
    
    if ($unit) {
        return round($size * pow(1024, stripos('bkmgtpezy', $unit[0])));
    }
    
    return round($size);
    }
    
    // Get configured limits
    $phpMaxPostSize = parse_size(ini_get('post_max_size'));
    $phpMaxUploadFileSize = parse_size(ini_get('upload_max_filesize'));
    
    if ($_SERVER['REQUEST_METHOD'] == 'POST') {
    // Check if $_POST and $_FILES are empty, which can indicate post_max_size was exceeded
    if (empty($_POST) && empty($_FILES) && $_SERVER['CONTENT_LENGTH'] > 0) {
        echo "<h2 style='color: red;'>Upload Failed: POST data too large!</h2>";
        echo "This usually means the total size of your request (files + form data) exceeded the 'post_max_size' limit.<br>";
        echo "Current 'post_max_size' setting: " . ini_get('post_max_size') . "<br>";
        echo "Current 'upload_max_filesize' setting: " . ini_get('upload_max_filesize') . "<br>";
        echo "Please ensure 'post_max_size' >= 'upload_max_filesize'.<br>";
        echo "Content-Length header received: " . $_SERVER['CONTENT_LENGTH'] . " bytes.<br>";
        // Optionally, you might log this as a warning or error.
    } elseif (isset($_FILES['userFile']) && $_FILES['userFile']['error'] == UPLOAD_ERR_OK) {
        $file = $_FILES['userFile'];
    
        // Existing upload_max_filesize check
        if ($file['size'] > $phpMaxUploadFileSize) {
            echo "Error: The uploaded file exceeds the server's configured 'upload_max_filesize' of " . ini_get('upload_max_filesize') . ".<br>";
        } else {
            // ... (rest of your successful file move logic)
            $targetDir = "uploads/";
            if (!is_dir($targetDir) && !mkdir($targetDir, 0755, true)) {
                die("Failed to create upload directory.");
            }
            if (!is_writable($targetDir)) {
                die("Upload directory is not writable.");
            }
            $targetFile = $targetDir . basename($file['name']);
    
            if (move_uploaded_file($file['tmp_name'], $targetFile)) {
                echo "The file ". htmlspecialchars( basename( $file['name'])). " has been uploaded.<br>";
                echo "Size: " . round($file['size'] / 1024, 2) . " KB<br>";
                // Displaying other POST data if available
                if (!empty($_POST)) {
                    echo "Other POST data received: <pre>";
                    print_r($_POST);
                    echo "</pre>";
                }
            } else {
                echo "Sorry, there was an error uploading your file.<br>";
                echo "Error code: " . $file['error'] . "<br>";
            }
        }
    } else {
        // Handle other specific upload errors (from UPLOAD_ERR_ constants)
        if (isset($_FILES['userFile']['error'])) {
            switch ($_FILES['userFile']['error']) {
                case UPLOAD_ERR_INI_SIZE:
                    echo "Error: The uploaded file exceeds the 'upload_max_filesize' directive in php.ini.<br>";
                    break;
                // ... (other error cases from previous example)
                case UPLOAD_ERR_NO_FILE:
                    echo "Error: No file was uploaded. This can also happen if the file was too large for 'post_max_size' if no other files were submitted.<br>";
                    break;
                default:
                    echo "An upload error occurred (code: " . $_FILES['userFile']['error'] . ").<br>";
                    break;
            }
        } else {
            echo "No file uploaded or an unexpected error occurred.<br>";
        }
    }
    } else {
    echo "Please use the form to upload files.<br>";
    }
    
    ?>

    6. memory_limit

    • Default Value: 128M
    • Value Type: Bytes (shorthand notation: K, M, G)
    • Description: Sets the **maximum amount of memory** in bytes that a script is allowed to allocate. While not directly a file upload limit, it’s crucial for scripts that process uploaded files, especially large ones.

    Why it matters:

    If memory_limit is less than post_max_size, PHP might struggle to even process the incoming POST request, especially when move_uploaded_file() or other file operations require memory. For example, resizing a large image requires significantly more memory than the image’s file size.

    Code Example: Monitoring Memory Usage

    This example illustrates how to check and monitor memory usage, which is key when processing large files.

    <?php
    
    // Set a temporary memory limit for this script for demonstration
    // In a real scenario, this would be configured in php.ini
    // ini_set('memory_limit', '256M'); // For demonstration, if your php.ini is lower
    
    echo "Current memory_limit: " . ini_get('memory_limit') . "<br>";
    echo "Initial memory usage: " . round(memory_get_usage(true) / 1024 / 1024, 2) . " MB<br>";
    
    // Simulate processing a large file (e.g., reading it into a variable)
    // NOTE: This will only work if 'upload_max_filesize' and 'post_max_size' allow the file.
    $largeFilePath = 'uploads/very_large_image.jpg'; // Assume a large file exists here
    
    if (file_exists($largeFilePath)) {
    echo "<hr>Attempting to read a large file into memory...<br>";
    $fileContent = file_get_contents($largeFilePath); // This can consume a lot of memory
    
    if ($fileContent === false) {
        echo "<p style='color: red;'>Failed to read file into memory. This could be due to memory_limit.</p>";
    } else {
        echo "File size: " . round(strlen($fileContent) / 1024 / 1024, 2) . " MB<br>";
        echo "Memory usage after reading file: " . round(memory_get_usage(true) / 1024 / 1024, 2) . " MB<br>";
        unset($fileContent); // Free up memory
        echo "Memory usage after unsetting content: " . round(memory_get_usage(true) / 1024 / 1024, 2) . " MB<br>";
    }
    } else {
    echo "<p>For a full demonstration, place a large file (e.g., >50MB) at 'uploads/very_large_image.jpg'.</p>";
    echo "Memory usage after initial checks: " . round(memory_get_usage(true) / 1024 / 1024, 2) . " MB<br>";
    }
    
    ?>

    7. max_execution_time

    • Default Value: 30
    • Value Type: Integer (Seconds)
    • Description: The **maximum number of seconds** a script is allowed to run before it is terminated by the PHP parser. This affects post-upload processing.

    Why it matters:

    For long-running tasks after an upload (like video encoding or large data imports), this limit is crucial. A script that consistently hits this limit needs its php.ini increased or its logic optimized.

    Code Example: Extending Execution Time

    <?php
    
    echo "Current max_execution_time: " . ini_get('max_execution_time') . " seconds<br>";
    
    // Simulate a long-running post-upload process
    echo "Starting simulated heavy processing...<br>";
    // ini_set('max_execution_time', 300); // Only works if PHP_INI_USER or PHP_INI_ALL
    set_time_limit(300); // Safer way to extend execution time at runtime if allowed
    
    $startTime = time();
    $duration = 10; // Simulate 10 seconds of work for demonstration
    
    // If max_execution_time is 30, and $duration is 40, this would timeout without set_time_limit
    for ($i = 0; $i < $duration; $i++) {
    // Perform some CPU-intensive task or sleep
    sleep(1); // Simulate work, e.g., processing a chunk of a large file
    echo "Processing... " . ($i + 1) . " seconds passed.<br>";
    flush(); // Send output to the browser immediately
    ob_flush(); // Ensure output buffer is flushed
    }
    
    $endTime = time();
    echo "Simulated processing finished in " . ($endTime - $startTime) . " seconds.<br>";
    
    ?>

    8. max_input_time

    • Default Value: 60
    • Value Type: Integer (Seconds)
    • Description: The **maximum time** in seconds a script is allowed to parse input data, including file uploads. This is the timeout that typically affects the **actual uploading phase** of a file.

    Why it matters:

    Crucial for users with slower internet connections or when uploading very large files. If uploads consistently fail with no clear error other than the script terminating mid-upload, increasing max_input_time is often the solution.

    Code Example: Understanding max_input_time

    This setting works behind the scenes during the POST request. You can’t directly “code around” it like max_execution_time with set_time_limit() because the script hasn’t fully started processing yet. You primarily configure it in php.ini.

    <?php
    
    echo "Current max_input_time: " . ini_get('max_input_time') . " seconds<br>";
    echo "<p><em>This setting primarily impacts the time it takes for the browser to send all POST data (including files) to the server. If a large file upload takes longer than this value, the script will terminate prematurely.</em></p>";
    
    ?>

    Conclusion

    Properly configuring these php.ini directives is paramount for any application that handles file uploads. While the defaults are often suitable for small personal sites, enterprise-level applications or those dealing with large media files will undoubtedly require careful tuning.

    Always remember the hierarchy of limits (memory_limit >= post_max_size >= upload_max_filesize), and combine server-side configuration with robust application-level validation and error handling for the most secure and reliable file upload experience.

    Happy coding!

    ini ini_get() ini_set() php settings
    Facebook Twitter Reddit Email Copy Link
    Previous ArticleSecure File Uploads Prevent Code Execution and Inclusion
    Next Article Using phpinfo() to Debug Common and Not-so-Common PHP Errors and Warnings

    Related Posts

    Development

    Using phpinfo() to Debug Common and Not-so-Common PHP Errors and Warnings

    September 28, 2025
    Development

    Secure File Uploads Prevent Code Execution and Inclusion

    September 28, 2025
    Leave A Reply Cancel Reply

    For security, use of Google's reCAPTCHA service is required which is subject to the Google Privacy Policy and Terms of Use.

    Continue Reading

    Introducing LinuxONE 5 and trends for 2025

    Databases

    Enterprise-grade natural language to SQL generation using LLMs: Balancing accuracy, latency, and scale

    Machine Learning

    Building Scalable APIs with Node.js and TypeScript

    Development

    Infortrend NAS CS4000U Storage Cost and Price in India – Affordable and Reliable

    Web Development

    Highlights

    Development

    Why CTEM is the Winning Bet for CISOs in 2025

    May 19, 2025

    Continuous Threat Exposure Management (CTEM) has moved from concept to cornerstone, solidifying its role as…

    Key Factors to Consider Before Hiring React Native Developers for Your Project🔍

    April 22, 2025

    Add Notes Functionality to Eloquent Models With the Notable Package

    August 23, 2025

    Building a Task Reminder With Laravel and MongoDB

    June 24, 2025
    © DevStackTips 2025. All rights reserved.
    • Contact
    • Privacy Policy

    Type above and press Enter to search. Press Esc to cancel.