Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
services:
webserver:
image: nginx:stable-alpine
restart: unless-stopped
volumes:
- ./index.php:/var/www/html/index.php
- ./docker/nginx/conf.d:/etc/nginx/conf.d
working_dir: /var/www/html
ports:
- "8080:80"
depends_on:
- php

php:
image: php:8.4-fpm-alpine
restart: unless-stopped
environment:
MAX_FILE_SIZE: 1024000
volumes:
- ./index.php:/var/www/html/index.php
- ./missing_timezones:/var/www/html/missing_timezones
22 changes: 22 additions & 0 deletions docker/nginx/conf.d/default.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.php index.html;
server_name _;
client_max_body_size 16M;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
44 changes: 31 additions & 13 deletions index.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
<?php
// Define constants
define('MAX_FILE_SIZE', 819200); // 800 kB
declare(strict_types=1);

const DEFAULT_MAX_FILE_SIZE = 819200;

$maxFileSize = getenv('MAX_FILE_SIZE', true);

if ($maxFileSize === false) {
$maxFileSize = DEFAULT_MAX_FILE_SIZE;
}

define('MAX_FILE_SIZE', $maxFileSize);
define('MISSING_TIMEZONES_FILE', __DIR__ . '/missing_timezones');

// Main execution
Expand All @@ -17,7 +26,8 @@
}

// Function to get the ICS URL from the query parameter
function getIcsUrl() {
function getIcsUrl()
{
if (!isset($_GET['ics_url']) || empty($_GET['ics_url'])) {
outputInstructions();
exit;
Expand All @@ -26,7 +36,8 @@ function getIcsUrl() {
}

// Function to display usage instructions
function outputInstructions() {
function outputInstructions()
{
echo "<h1>ICS Timezone Fixer</h1>";
echo "<p>This tool modifies a provided .ics calendar file to include missing timezones, ensuring accurate event times in Google Calendar and other apps.</p>";
echo "<h2>How to Use:</h2>";
Expand All @@ -41,7 +52,8 @@ function outputInstructions() {
}

// Function to validate the provided URL and enforce HTTPS
function validateUrl($url) {
function validateUrl($url)
{
if (!filter_var($url, FILTER_VALIDATE_URL)) {
throw new Exception('Invalid URL.');
}
Expand All @@ -54,7 +66,8 @@ function validateUrl($url) {
}

// Function to validate the file content by downloading a small portion
function validateFileContent($url) {
function validateFileContent($url)
{
$ch = curl_init($url);
if ($ch === false) {
throw new Exception('Failed to initialize cURL for partial content download.');
Expand All @@ -63,7 +76,7 @@ function validateFileContent($url) {
$partialContent = '';
$maxBytes = 1024; // Read first 1 KB

$writeFunction = function($ch, $data) use (&$partialContent, $maxBytes) {
$writeFunction = function ($ch, $data) use (&$partialContent, $maxBytes) {
$length = strlen($data);
$partialContent .= $data;
if (strlen($partialContent) >= $maxBytes) {
Expand Down Expand Up @@ -97,7 +110,8 @@ function validateFileContent($url) {
}

// Function to fetch the ICS content with a size limit
function fetchIcsContent($url, $maxFileSize) {
function fetchIcsContent($url, $maxFileSize)
{
$ch = curl_init($url);
if ($ch === false) {
throw new Exception('Failed to initialize cURL.');
Expand All @@ -107,7 +121,7 @@ function fetchIcsContent($url, $maxFileSize) {
$totalDownloaded = 0;

// Define the write function callback
$writeFunction = function($ch, $data) use (&$icsContent, &$totalDownloaded, $maxFileSize) {
$writeFunction = function ($ch, $data) use (&$icsContent, &$totalDownloaded, $maxFileSize) {
$length = strlen($data);
$totalDownloaded += $length;

Expand All @@ -130,7 +144,7 @@ function fetchIcsContent($url, $maxFileSize) {
if ($result === false) {
if (curl_errno($ch) == CURLE_WRITE_ERROR && $totalDownloaded > $maxFileSize) {
curl_close($ch);
throw new Exception('The ICS file exceeds the maximum allowed size of 800 kB.');
throw new Exception(sprintf('The ICS file exceeds the maximum allowed size of %d kB.', $maxFileSize / 1024));
} else {
$error = curl_error($ch);
curl_close($ch);
Expand All @@ -144,7 +158,8 @@ function fetchIcsContent($url, $maxFileSize) {
}

// Function to read the missing timezones from the side file
function readMissingTimezones($filename) {
function readMissingTimezones($filename)
{
if (!file_exists($filename)) {
throw new Exception('Missing timezones file not found.');
}
Expand All @@ -158,7 +173,8 @@ function readMissingTimezones($filename) {
}

// Function to insert missing timezones into the ICS content
function insertMissingTimezones($icsContent, $missingTimezones) {
function insertMissingTimezones($icsContent, $missingTimezones)
{
$pos = strpos($icsContent, 'BEGIN:VEVENT');
if ($pos === false) {
throw new Exception('Invalid ICS file format.');
Expand All @@ -170,11 +186,13 @@ function insertMissingTimezones($icsContent, $missingTimezones) {
}

// Function to output the modified ICS content with appropriate headers
function outputIcsContent($modifiedIcsContent) {
function outputIcsContent($modifiedIcsContent)
{
// Now that everything is validated and modified, set the content type headers
header('Content-Type: text/calendar; charset=utf-8');
header('Content-Disposition: attachment; filename="modified_calendar.ics"');

echo $modifiedIcsContent;
}

?>