Monday, March 15, 2021

the joy of trivial webapps in php - calorie tracker with graph

I'm pretty open with the idea that, if I didn't exercise care, my weight would go up. (And I don't judge people who are heavier than they'd prefer! It's super tough.)

Actually for a long time I've been tracking my weight and even sharing the graph online: diet.kirk.is goes all the way back to 1999!

Here's what I said about weightloss in 2018 and I think is still true:
Still the best diet plan comes from the book "Chubster: A Hipster's Guide to Losing Weight While Staying Cool" and also "The Hacker's Diet": "find a method to hit a daily calorie count without making yourself miserable" I doubt there's an all-in-one for everyone, but so many successful diets boil down to that.
It's the "miserable" bit that's the real sticker, since eating is so emotional! I've had to learn and leverage lots of details about my body's hunger cycle: famished midday, not so hungry in the evenings, not really needing variety but definitely needing its sweettooth satiated.

Anyway, in trying not to gain back ALL the weight I lost over quarantine (24% of people gained weight but 17% lost - again, eating is emotional!) for a few weeks I've been keeping a simple text entry in "Simplenote" to track my eating over the course of a day. (I've used nerdy apps before, doing all those lookups, but they're always so many screens, back and forth, lots of tip tapping... somehow text files just feel nice). Eventually I settled on a "calories - item name" format that was easy to visually scan and run the sums for. 

But then I thought - I can build a simple webpage to help keep track. Here's what I came up with:


As you can see, geared to be mobile friendly at least :-D It makes a graph of what entered previously, it sums the total, there's a little date picker than can change to a different day, as well as a list of entries below. 

Anyway, it's such a delight to be able to spend an hour or so and make this for myself. I wish every one was so empowered! It's just 3 files. Here's the main index.php: (that viewport line helps with the mobile friendly aspect)

index.php:
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<?
    if(isset($_GET["date"])) {
        $date = $_GET["date"];   
    } else {
        $date = date("Y-m-d");   
    }
    
    if(!preg_match("/^\d\d\d\d\-\d\d\-\d\d$/",$date)) {
        die;
    }
    
    print "<title>food - $date</title>";
    
    if(file_exists("data/$date")){
        $guts = file_get_contents("data/$date");
    }
    
?>
<link rel="stylesheet" href="style.css" />
</head>
<body>
  <div class="content">
        <h1>food - <? echo $date; ?></h1>
        <table class="chart">
        <?
            if(isset($guts)) {
                $lines = explode("\n",$guts);
                $total = 0;
                foreach($lines as $line) {
                    if(preg_match("/^(\d*) \- (.*)$/",$line,$matches)){
                        $cal = $matches[1];
                        $total += $cal;
                        $width = $cal / 5;
                        $food = $matches[2];
                        print "<tr><td>$food</td>\n";
                        print "<td><div style='width:".$width."px'></div></td></tr>\n";
                    }
                }
                print "<tr><td><br><b>total: $total</b></td></tr>";                
            }      
        ?>
        
        </table>
        
        <form action="save.php" method="post">
            <input name="date" type="date" value="<? echo $date; ?>" 
                onchange="window.location='./?date='+this.value">
            <textarea name="guts"><? echo $guts ?></textarea>
            <button>submit</button>
        </form>
  
        <ul>
        <?
            $files = array_values(array_diff(scandir("data"), array('.', '..')));
            foreach($files as $date){
                print "<li><a href='./?date=$date'>$date</a>";   
            }
        
        ?>
        </ul>
  </div>
</body>
</html>
I depend on security through obscurity and htauth for this kind of stuff. Since I am writing/reading files on my webserver, I do sanity check that files names match ####-##-## formats only. I like the little "onchange" I made with the html5 date field to navigate, and the graph-in-table is reasonably elegant. 

There's also a tad of CSS:

style.css
body {
    background-color: white;
    color: black;
    font-family: sans-serif;    
}
.content {
    width: 800px;
    margin: auto;
}
input,textarea {
    display:block;   
    margin-bottom:10px;
}
textarea {
    width:20em;
    height:20em;
}
button {
    font-size:40px;   
}

.chart div {
    height:20px;
    background-color: #ccc;
}
Slightly clever using display:block,I guess, to get things to line up smartly.
And then the file saving is trivial, just save the file and go back to the day, which will display it.

save.php
<?
    $date = $_POST["date"];
    if(!preg_match("/^\d\d\d\d\-\d\d\-\d\d$/",$date)) {
        die;
    }
    $guts = $_POST["guts"];
    file_put_contents("data/$date",$guts);
    header("Refresh:0; url=./?date=$date");
?>

UPDATE:

Not that anyone cares but I updated this a little, changed the order of things so the textarea was first in the tab order and did a

onfocus="this.selectionStart = this.selectionEnd = this.value.length;"
to hop the cursor to the end, and made the regex more robust:

"/^(\d+) ? ?\-? ? ?(.*)$/"
The lets it use space dash space, but omit either the dash or the space, or add an extra space or two.

No comments:

Post a Comment