A Custom Server for Shottr
I wrote a PHP script to act as custom cloud server for receiving and storing screenshots from shottr
Created:
Shottr is a screenshotter, annotation tool for MacOS. One of the features available for “Friends of the Proejct” (a paid tier) is the ability to upload the screenshot to their cloud. While handy, I want to own my data.
The developer of this application supports that option via setting a custom web server via command line.
To use a custom screenshot uploading endpoint
$ defaults write cc.ffitch.shottr uploadEndpoint 'https://mysite.com/endpoint'
I wrote a simple PHP web application to act as the server that will receive the upload and save it to a directory.
I have modified nginx
so that the screenshot can be
served from under the screenshots
directory on this
website.
The PHP code is given below as reference. I wrote most of this with the help of GPT.
Notes:
- The uploaded image filenames are a base58 representation of the timestamp.
- The screenshot captured by the Shottr app is uploaded to the server
by pressing
Command-e
- Update - Aug 11, 2024: The program now saves the image in
.webp
format at 80% quality for much smaller filesizes. The program is updated below. The improvement was made by Anthropic Claude 3.5 Sonnet, in one shot.
<?php
// Define the destination directory
$uploadDirectory = "/var/www/www.yoursite.com/screenshots/";
// Image Directory
$imageUrlBase = "https://www.yoursite.com/screenshots/";
// Log the information to a log file
$logFile = "/tmp/fileuploader.txt";
//timestamp
$timestamp = date("Y-m-d H:i:s");
$now = date("YmdHis");
// https://www.darklaunch.com/base58-encode-and-decode-using-php-with-example-base58-encode-base58-decode.html
function base58_encode($num)
{$alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
$base_count = strlen($alphabet);
$encoded = "";
while ($num >= $base_count) {
$div = $num / $base_count;
$mod = $num - $base_count * intval($div);
$encoded = $alphabet[$mod] . $encoded;
$num = intval($div);
}
if ($num) {
$encoded = $alphabet[$num] . $encoded;
}
return $encoded;
}
function base58_decode($num)
{$alphabet = "123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ";
$len = strlen($num);
$decoded = 0;
$multi = 1;
for ($i = $len - 1; $i >= 0; $i--) {
$decoded += $multi * strpos($alphabet, $num[$i]);
$multi = $multi * strlen($alphabet);
}
return $decoded;
}
function convertToWebP($inputFile, $outputFile, $quality = 80)
{$command = "cwebp -q $quality $inputFile -o $outputFile";
exec($command, $output, $returnCode);
if ($returnCode !== 0) {
throw new Exception("Failed to convert image to WebP format.");
}
}
// Function to log data to the file
function logData($data)
{global $logFile;
global $timestamp;
// Get the current timestamp
$timestamp = date("Y-m-d H:i:s");
// Format the data
$logData = "[$timestamp] " . $data . PHP_EOL;
// Append the data to the log file
file_put_contents($logFile, $logData, FILE_APPEND);
}
// Check if a file was uploaded
if (!isset($_FILES["file"])) {
echo "ERR: No file uploaded.";
exit();
}
// Get the uploaded file details
$file = $_FILES["file"];
$fileName = $file["name"];
$tmpFilePath = $file["tmp_name"];
$fileContent = file_get_contents($tmpFilePath);
$newFileName = base58_encode($now) . ".webp";
$target = $uploadDirectory . $newFileName;
try {
// Convert the uploaded image to WebP format
$tmpFilePath, $target);
convertToWebP(unlink($tmpFilePath);
catch (Exception $e) {
} $msg =
"ERR: Failed to convert and save the uploaded file - " .
$e->getMessage() .
PHP_EOL;
echo $msg;
unlink($tmpFilePath);
exit();
}
$logData =
"Client IP=" .
$_SERVER["REMOTE_ADDR"] .
" Filename=" .
$newFileName .
PHP_EOL;
$logData);
logData($imageURL = $imageUrlBase . $newFileName;
echo "SUCCESS: " . $imageURL;
?>
The corresponding nginx config is:
location /screenshots {
alias /var/www/www.yoursite.com/screenshots;
}