PHP: Serve file for download

If you want to a simple way to serve a file for download in PHP you can use this function:

function serve_file($filepath) {
    $filename = basename($filepath);

    if (headers_sent()) {
        die("Cannot output file because output already started");
    }

    $mime_type = mime_content_type($filepath);
    header("Content-type: $mime_type");
    header("Content-Disposition: attachment; filename=\"$filename\"");

    readfile($filepath);

    exit(0);
}
Leave A Reply

Perl: Loop through an array an extract pairs of variables

I had an array that I wanted to iterate through and extract pairs of variables. I found this pretty neat way to do that:

Perl:

my @arr = ("red", "green", "blue", "yellow", "orange", "purple");

while (@arr) {
    my ($x, $y) = splice(@arr, 0, 2);
    print "$x:$y\n";
}

I found a bunch of different ways to do this, and benchmarked them.

PHP:

$arr = ["red", "green", "blue", "yellow", "orange", "purple"];

while ($arr) {
    [$x, $y] = array_splice($arr, 0, 2);
    print "$x:$y<br />";
}

Note: You need to be careful you have an even number of elements or you will get undefined variable errors.

Leave A Reply

Perl: Glob recursively

I wrote a simple function to let you glob a directory recursively. It's limited to a single path/glob pattern, but that's good enough for now.

use File::Find;

my @files = globr("/etc/*.cfg");

sub globr {
    my ($str)       = @_;
    my ($dir,$glob) = $str =~ m/(.*\/)(.*)/;

    $dir  ||= './'; # Only a glob, so assume current dir
    $glob ||= $str; # No dir only a glob: *.pl

    # Find all the dirs in the target dir so we can recurse through them later
    my (@ret, @dirs);
    find( { wanted => sub { if (-d $_) { push(@dirs, $_) } }, no_chdir => 1 }, $dir);

    # Go through each dir we found above and glob in them for matching files
    foreach my $dir (@dirs) {
        my @g = glob("$dir/$glob");
        push(@ret, @g);
    }

    return @ret;
}

See also: Find files recursively

Leave A Reply

Perl: Prepend a script before script execution

I need to prepend some code before I run my Perl script. In my prepended script I will set some debug variables and add some debugging subroutines. The easiest way I've found to do this is with the -I and -M parameters. This allows you to set an include directory, and a specific module to be loaded before your script starts.

I was able to create a debug.pm in my /tmp/ directory and prepend it to my Perl script like this:

perl -I/tmp/ -Mdebug my_script.pl

This tells Perl to add /tmp/ to the list of locations to look for modules, and then to load the module debug. Then you simply make a debug.pm that includes the global variables you want to include and your main script will be able to read them.

Leave A Reply

Oral Rehydration Solution Recipes

I found these recipes on a post related to Liquid I.V. and Drip Drop. I'm going to copy them here just in case.

Orange juice base

3/4 tsp salt
8 tsp sugar
1 cup unsweetened orange juice without pulp
4 1/2 cups of water

Grape juice base

1/2 cup juice
3 1/2 cups water
1/2 tsp salt

Gatorade base

Choose any flavor, except red
2 cups Gatorade
2 cups water
1/2 tsp salt

Apple juice base

1 cup of juice
3 cups of water
1/2 tsp salt

Leave A Reply

Perl: Find files recursively

I needed to search recursively through a directory structure for files that matched a specific pattern. The simplest way that I found was using File::Find. I wrote a simple wrapper function to make searching simpler and more straight-forward. It uses regular expression matching so it should be quite flexible.

# All the files that end in .pl
my @perl_files = find_recurse(qr/\.pl$/, "/home/user/");
# Anything with kitten in the name
my @kittens    = find_recurse(qr/kitten/, "/home/user/");
# All .mp3 and .ogg files
my @aud_files  = find_recurse(qr/\.(mp3|ogg)$/, "/home/user/");
# Search two directories
my @cfg_files  = find_recurse(qr/\.cfg$/, ("/tmp/", "/etc/"));
use File::Find;

# Recursively search for files matching a pattern
sub find_recurse {
    my ($pattern, @dirs) = @_;
    if (!@dirs) {
        @dirs = (".");
    }

    my @ret = ();
    find(sub { if (/$pattern/) { push(@ret, $File::Find::name) } }, @dirs);

    return @ret;
}
Leave A Reply

Disable Caps Lock and Num Lock

The only time I ever hit the Caps Lock key is by accident. When I do it messes up everything that I'm working on and I have to go back and fix things. Same thing with Num Lock! If you use these quick xmodmap commands you can disable those keys and avoid some headaches.

# Disable: Capslock, Numlock
xmodmap -e "keycode 66 ="
xmodmap -e "keycode 77 ="
Leave A Reply

Winamp: Opus plugin for Winamp

Winamp will always have a special place in my heart. Luckily it's still semi-maintained and runs great on Windows 10. It plays a bunch of audio files types out of the box, but lacks .opus support. Luckily someone wrote a plug-in to read opus files.

I've mirrored it here just in case.

Leave A Reply

Perl: Parse Linux log time strings

Linux has a common date/time format used in logs that looks like May 4 01:04:16. Often I will need to parse that into a unixtime so I wrote a function to do it so I won't have to reinvent the wheel next time:

use Time::Piece;

my $epoch = linux_timestr("May  4 01:04:16");

sub linux_timestr {
    my $time_str = shift();
    # Since this string type doesn't include the year we append the current
    # year to make the calculations correct. Otherwise we get 1970
    my $year     = (localtime())[5] + 1900;
    $time_str   .= " $year";

    my $format = "%b %d %H:%M:%S %Y";
    my $x      = localtime->strptime($time_str, $format);

    return $x->epoch();
}

Other common formats are cdate and ISO 8601

# cdate
my $x = localtime->strptime("Sat May  8 21:24:31 2021", "%a %b %d %H:%M:%S %Y");
# ISO 8601
my $y = localtime->strptime("2000-02-29T12:34:56", "%Y-%m-%dT%H:%M:%S");
Leave A Reply

PHP: Either function because PHP lacks a good "or"

PHP lacks a good "or" comparison operator. Neither the or operator, nor the || return a value. I wrote a function that will take two (or more) variables and return the first one that has a non-zero value.

$limit = $array_count || 15;       // true (bad!)
$limit = either($array_count, 15); // 15 (good!)

function either() {
    $items = func_get_args();

    // Return the first non-empty item
    foreach ($items as $x) {
        if (!empty($x)) {
            return $x;
        }
    }

    return null;
}
Leave A Reply

Perl: Rounding a number

If you need to round a number in Perl you can use the POSIX method round(). If for some reason you don't want to use the POSIX method I wrote a pure Perl version of round() that is pretty fast.

use POSIX;

my $num = 3.14156;

print(POSIX::round($num)); # 3
print(round($num));        # 3

sub round {
    my $num = shift();

    if ($num < 0) {
        $ret = int($num - 0.5);
    } else {
        $ret = int($num + 0.5);
    }

    return $ret;
}

Along with round, sometimes you want "round to the nearest X", which I also implemented:

sub nearest {
    my ($num, $nearest) = @_;

    my $div = $num / $nearest;
    my $ret = round($div) * $nearest;

    return $ret;
}
Leave A Reply

PHP: Increment a hash variable in an E_NOTICE friendly way

I have a hash that contains counts for a bunch of stats. Unfortunately you can't just increment a hash like: $hash['key']++ and have it be E_NOTICE compliant. If that key does not exist in the array and you try and increment it you will trigger an E_NOTICE alert. I wrote this quick increment implementation that will allow you to increment a non-existing key.


$hash = [];

incr($hash['key']); // Inits to 1
incr($hash['key']); // Sets to 2

// Increment a variable (E_NOTICE compatible)
function incr(&$i, $value = 1) {
    // If the value is already there add to it
    if (isset($i)) {
        $i += $value;
    // If the value isn't there, just set it initially
    } else {
        $i = $value;
    }
}
Leave A Reply

Perl: Calculate ellapsed milliseconds

In Perl if you want to calculate time in milliseconds (thousandths of a second) you can use Time::HiRes and the time() function.

use Time::HiRes qw(time);

my $start = time();

# Stuff you want to time here

my $elapsed = time() - $start;

printf("%0.2f seconds\n", $elapsed);
printf("%0.1f milliseconds\n", $elapsed * 1000);
printf("%d microseconds\n", $elapsed * 1000 * 1000);
printf("%d nanoseconds\n", $elapsed * 1000 * 1000 * 1000);
Leave A Reply

PHP: Set a threshold to limit API access

I have an API that I want to allow outside access to, but it needs to be protected from abuse. I wanted to limit the number of hits from a given source in a way that does not require tracking every single hit in database. Specifically I wanted a method to track millions of sources without requiring insane amounts of disk or memory.

I ended up with the concept of a "bucket" of hits in a given time window. This groups all the hits for a source into a bucket of time which makes it easier to track. My back of the envelope math means that each source should require between 40 and 50 bytes of memory to track. This makes it feasible to track and limit a million clients using about ~50MB of memory. Some type of caching system is required. Memcached, Redis, or a simple in-memory key/value cache would work perfectly.

You can view my proof-of-concept code, and view the raw PHP. This example uses Memcached.

Leave A Reply

Bash: History size and timestamp

Bash defaults to logging 1000 entries to the history. I increased that limit by adding the following line to my ~/.bashrc

export HISTSIZE=5000           # the bash history should save 5000 commands
export HISTTIMEFORMAT="%F %T " # Store the timestamps of each command also

Previously

Leave A Reply