Skip to content

Instantly share code, notes, and snippets.

@kirb
Last active November 16, 2020 22:39
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save kirb/1922421 to your computer and use it in GitHub Desktop.
Save kirb/1922421 to your computer and use it in GitHub Desktop.
Self-hosted Cydia repo download counter
# Use the Apache rewrite engine to redirect downloads to our script.
RewriteEngine On
RewriteBase /
RewriteRule ^repo/((Packages|Release)(.*)?)$ /repo/counter.php?filename=$1 [L,QSA]
RewriteRule ^repo/downloads/(.*)\.deb$ /repo/counter.php?filename=$1 [L,QSA]

How to add a download counter to a self-hosted Cydia repository

2018-04-22: This is pretty old, possibly broken on newer PHP, and the original blog post that accompanied it is lost to time. I’m keeping this here for posterity and you’re free to use it, but please consider other “download counter” scripts instead (doesn’t need to be Cydia-specific — they’re all the same thing).

Installation

  1. Click the download link at the top of the gist page and extract the zip.
  2. Open counter.php and .htaccess in your favorite editor (not Notepad).
  3. In counter.php, scroll down to the line that says $link = mysqli_connect( ... and change the parameters to the ones you use to connect to MySQL.
  4. Go down to the mysqli_select_db($link, "myrepodb") line and change myrepodb to the name of your database.
  5. Run the downloads.sql file in your MySQL database. In phpMyAdmin, you can use the Import tab to do this.
  6. Move your debs to a folder called downloads in your repo folder.
  7. Open the .htaccess file and replace repo with the path to the folder that your repo is in, relative to your document root (usually htdocs or public_html)
  8. Make 100,000% sure there is not a byte order mark at the start of counter.php by using the “save as UTF-8 without BOM” feature in your editor. In Notepad++ this is under the Encoding menu; in Sublime it’s under the File menu; in Visual Studio Code press Cmd/Ctrl-Shift-P and type in “encoding”.
  9. Upload and enjoy :)

Note this only collects the stats. It’s up to you to write something to display them.

<?php
function errorout($code, $message) {
// Makes dpkg know it's not a package
header("Content-Type: text/plain");
// Generate the HTTP error header
header($_SERVER["SERVER_PROTOCOL"] . " $code $message");
// Then print out the error.
// Because the content type is plain text, escaping is not necessary.
die($message);
}
$db = new mysqli("localhost", "myrepo", "mypassword"); // change parameters to what you use
if ($db->connect_error) {
errorout(500, "Couldn't connect to the database. Please try your download later.");
}
$db->set_charset("utf8")
or errorout(500, "Couldn't set up the database. Please try your download later.");
$db->select_db($link, "myrepodb") // change myrepodb to your database name
or errorout(500, "Couldn't open the database. Please try your download later.");
// Exit here if the filename hasn’t been provided.
if (!isset($_GET["filename"]) or empty($_GET["filename"])) {
errorout(404, "The file you requested either doesn't exist or isn't allowed to be downloaded.");
}
// Store the filename in a variable, escaping it to be safe.
$file = $db->real_escape_string($_GET["filename"]);
// Determine the file path.
// Packages and Release are expected to be in the same folder as this script.
// Anything else is expected to be in a downloads/ folder.
if ($file == "Packages" or strpos($file, "Packages.") === 0
or $file == "Release" or strpos($file, "Release.") === 0) {
$path = $file;
} else {
$path = "downloads/$file";
}
// The following code checks for attempts to read files that aren't debs.
// Not doing this lets attackers read PHP scripts and system files.
if (stristr($file, "..") or stristr($file, "/") or stristr($file, "\\") or !file_exists($file)) {
errorout(404, "The file you requested either doesn't exist or isn't allowed to be downloaded.");
}
// Count the download in the database
// A log will be saved if something goes wrong.
try {
// Check whether the package has already been downloaded.
// We select an empty string as we don’t read the result, we just want to know if the row exists.
$query = $db->query("SELECT '' FROM downloads WHERE filename='$file'");
if (!$query or $query->num_rows == 0) {
// If it doesn't exist, create the row
$db->query("INSERT INTO downloads SET filename='$file', count=1, first_download=NOW(), last_download=NOW()");
} else {
// If it does, add one to the counter
$db->query("UPDATE downloads SET count=count+1, last_download=NOW() WHERE filename='$file'");
}
} catch (Exception $e) {
// Something went wrong, so save a log file and continue onto the download
// (The document root is usually htdocs or public_html)
file_put_contents(dirname($_SERVER["DOCUMENT_ROOT"]) . "/../cydiaerr.log", print_r($e, true));
}
// Finally, serve the user the file they requested
$filesize = filesize($path);
// If it's more than 16 bytes long, it's ok to serve it
if ($filesize > 16) {
// Force browsers to download the file, not display it
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\"$file\"");
// Indicate how big the file is
header("Content-Length: " . $filesize);
// And finally, output the file!
// It’s important to use readfile() as this buffers the output (reads and outputs small amounts at a time).
// Reading the entire file into a string with file_get_contents() will use huge amounts of memory for bigger files.
readfile($path);
} else {
errorout(404, "The file you requested either doesn't exist or isn't allowed to be downloaded.");
}
CREATE TABLE `downloads` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`filename` text NOT NULL,
`first_download` datetime NOT NULL,
`last_download` datetime NOT NULL,
`count` int(11) NOT NULL DEFAULT 1,
PRIMARY KEY (`id`)
);
@Technologx2013
Copy link

What do we need to add to our depiction file?

@MattdaveMatt
Copy link

I get a Size mismatch in cydia when i enable this, but when it's not enabled it works fine. Any ideas?

@Nosskirneh
Copy link

I managed to solve the bugs. If you came all this way and getting "size mismatch" in Cydia; try my fork of this repository. I use nginx instead of apache's .htaccess, but you can use the .htaccess from this repo if you're not a nginx user.

@kirb
Copy link
Author

kirb commented Apr 22, 2018

Just updated to clean up a bit and add a disclaimer. I haven’t written PHP in ages and haven’t used this script in ages so it may be completely broken, or it might work great! If it works (hopefully), you can use it but be aware that I’m not supporting it.

@0bash
Copy link

0bash commented Aug 7, 2018

can you help me?
i have a trouble

@jailbreakaz
Copy link

What do we need to add to our depiction file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment