Getting Started: Your First Snuze Script
Ready to jump in and get started? This section walks through the process of installing Snuze and using it to write a basic script that interacts with Reddit's API. When you're finished, you'll have a script that periodically checks your favorite low-volume subreddit for new posts, and sends you an email alert if it finds any.
Contents
- Your Environment
- Installing Snuze
- Writing Your Script
- tl;dr? The completed script
- Run Your Script
- Scheduling
Your Environment
Before getting underway, here are some things you're going to need:
- Access to a machine with the PHP 7.2+
command line binary installed. This means you should be able to open a shell
or command prompt, run
php -v
, and get output similar to this:
[user@host ~]$ php -v PHP 7.3.9 (cli) (built: Sep 1 2019 12:47:11) ( ZTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.3.9, Copyright (c) 1998-2018 Zend Technologies
-
For the example script, it helps if PHP is configured to send email; if not, don't worry about it.
-
Composer to install Snuze
-
A Reddit account. It's suggested you create a new account just for using Snuze, so if your scripts or server are ever compromised, no one gets the password to your main Reddit account.
-
A client ID and secret you've obtained from Reddit. See the "First Steps" listed here (stop once you have your app's client ID and secret).
Installing Snuze
Snuze source code is available directly from GitHub and from Packagist.
It's strongly encouraged that you use Composer to install Snuze. This is the only supported installation method.
Create and change to a new directory where you want to work; then
run composer require --dev snuze/snuze
to pull in Snuze:
[user@host ~]$ mkdir mybot && cd mybot [user@host ~/mybot]$ composer require --dev snuze/snuze Using version ^0.8.0 for snuze/snuze ./composer.json has been created Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 2 installs, 0 updates, 0 removals - Installing parseword/pickset (v1.0.2): Loading from cache - Installing snuze/snuze (v0.8.0): Downloading (100%) Writing lock file Generating autoload files
The --dev
is critical, as the current release version is < 1.0. This will install
Snuze inside of Composer's standard vendor
directory structure, with the
autoloader built for you.
Writing Your Script
Recall that we're making a script to periodically check a subreddit for
new posts and notify you when it finds some. To that end, think of a subreddit
you're interested in, which only gets a handful of posts each day or week. The
example code will use /r/CentOS
, the subreddit about CentOS Linux.
The strategy
The logic for this script will be:
- Load and configure Snuze
- Get the last-run timestamp for this script
- Fetch the newest posts from the subreddit
- Check for unseen posts
- If there are some, send a notification email
- Update the last-run time
We'll track the script's last-run timestamp in a text file in the same directory as the script itself.
Create your script file
Start by creating a new empty PHP file in your working directory, let's say sub-poller.php
,
and opening it in your editor or IDE.
Load and configure Snuze
Before you can use Snuze to interact with Reddit, you have to tell it how to authenticate with the API, and provide any other config options you want to use. For this example, we'll set the mandatory authentication parameters, and leave default settings for everything else.
The first part of any Snuze bot or script will look something like this:
<?php require_once __DIR__ . '/vendor/autoload.php'; /* Set authentication and configuration parameters */ $config = [ 'auth.client_id' => 'your-client-id-from-reddit', 'auth.client_secret' => 'your-secret-from-reddit', 'auth.username' => 'your-reddit-username', 'auth.password' => 'your-reddit-password', 'auth.user_agent' => 'php:YourAwesomeBot 1.2.3 (by /u/your-reddit-username)', ]; /* Pass the config array to a SnuzeFactory to get a Snuze object */ $snuze = (new \snuze\SnuzeFactory($config))->getSnuze();
This bit of code imports Composer's autoloader, creates an array with the
config options, and then uses
a SnuzeFactory
to get an
instance of Snuze. Copy and paste this code into your script. Edit the first 4
values in the $config
array to align with your Reddit account and app details.
Then, for the user agent, make up a bot name and version number, and include
your Reddit username in the string.
Get the last-run timestamp
Prior to fetching data from Reddit, let's figure out when the script last ran, so any posts older than that time can be ignored. Reddit uses the unix epoch as a timestamp, so we'll compare against that.
Add this code to your script:
/* Get the unix epoch at which this script was last executed */ $lastrun = (int) @file_get_contents('sub-poller-last-run.txt');
At this point, the script has never run (and that file doesn't exist yet).
The first time the script runs, $lastrun
will default to 0
and every post
will be treated as "new." On subsequent runs, only truly new posts will
generate an alert.
Fetch the newest posts from the subreddit
Now that you have a configured Snuze object, you can use it to interact with the Reddit API. It's time to get some data!
Snuze methods that retrieve data from Reddit have names beginning
with fetch
. There are methods to fetch posts ("links") from a subreddit in all
of the sort orders: hot, top, controversial, etc. We'll use
fetchLinksNew()
to get a collection of the most recent posts. Since the target subreddit doesn't
get much traffic, it should be sufficient to grab the most recent 25 posts.
Add this code to your script, specifying a different subreddit if you want:
/* Fetch the newest 25 posts from /r/CentOS */ $posts = $snuze->fetchLinksNew('centos', 25);
This one method call has a lot going on behind the scenes. Snuze will log you
in to the API, get an authentication token that's valid for the next hour,
store the token in a small SQLite data file in your script's directory,
request the most recent 25 posts from /r/CentOS
, turn them into
Link
objects, place those into a
LinkListing
,
and finally return the
LinkListing
to you.
Check for unseen posts
Calling fetchLinksNew()
returned a LinkListing
object. This is a collection that holds Link
objects, each of which represents a Reddit post. The LinkListing
is iterable, so you can call foreach()
on it and loop over its constituents.
Let's check for links that were posted since the last time the script was run. If any are found, some information about them will be added to an array. That array will be used to build a notification email.
Add this code to your script:
/* An array to hold any unseen posts */ $newPosts = []; /* Iterate over the posts retrieved from the Reddit API */ foreach ($posts as $p) { /* Was this post was created after the last-run timestamp? */ if ($p->getCreated() > $lastrun) { /* Add this post to the array */ echo "Found a new post: {$p->getTitle()}" . PHP_EOL; $newPosts[] = "<a href='https://reddit.com{$p->getPermalink()}'>{$p->getTitle()}</a>"; } }
Here, three methods from the Link
object were used:
getCreated()
, which returns the unix epoch when the post was madegetPermalink()
, which gets the relative URL of the post (we have to add the reddit.com part)getTitle()
, which returns the title of the post
Now, the script needs to send an email alert if it found anything new. Add this code to your script:
/* If there were unseen posts, send an email notification */ if (!empty($newPosts)) { $email = 'your-email@example.com'; $subject = 'New posts were found in /r/CentOS'; $body = 'Some new posts were found. Check them out: ' . PHP_EOL . PHP_EOL; $body .= join(PHP_EOL, $newPosts); mail($email, $subject, $body, 'From: ' . $email); }
Update the last-run timestamp
Finally the script needs to update its last-run timestamp. The next time it runs, it'll use the new timestamp when locating unseen posts. Add this code to the end of your script:
/* Update the last-run timestamp */ file_put_contents('sub-poller-last-run.txt', time());
The completed script
You should now have a completed script called sub-poller.php
that looks like
this, with your own authentication information in the $config
array, and
perhaps a subreddit other than /r/CentOS
:
<?php require_once __DIR__ . '/vendor/autoload.php'; /* Set authentication and configuration parameters */ $config = [ 'auth.client_id' => 'your-client-id-from-reddit', 'auth.client_secret' => 'your-secret-from-reddit', 'auth.username' => 'your-reddit-username', 'auth.password' => 'your-reddit-password', 'auth.user_agent' => 'php:YourAwesomeBot 1.2.3 (by /u/your-reddit-username)', ]; /* Pass the config array to a SnuzeFactory to get a Snuze object */ $snuze = (new \snuze\SnuzeFactory($config))->getSnuze(); /* Get the unix epoch at which this script was last executed */ $lastrun = (int) @file_get_contents('sub-poller-last-run.txt'); /* Fetch the newest 25 posts from /r/CentOS */ $posts = $snuze->fetchLinksNew('centos', 25); /* An array to hold any unseen posts */ $newPosts = []; /* Iterate over the posts retrieved from the Reddit API */ foreach ($posts as $p) { /* Was this post was created after the last-run timestamp? */ if ($p->getCreated() > $lastrun) { /* Add this post to the array */ echo "Found a new post: {$p->getTitle()}" . PHP_EOL; $newPosts[] = "<a href='https://reddit.com{$p->getPermalink()}'>{$p->getTitle()}</a>"; } } /* If there were unseen posts, send an email notification */ if (!empty($newPosts)) { $email = 'your-email@example.com'; $subject = 'New posts were found in /r/CentOS'; $body = 'Some new posts were found. Check them out: ' . PHP_EOL . PHP_EOL; $body .= join(PHP_EOL, $newPosts); mail($email, $subject, $body, 'From: ' . $email); } /* Update the last-run timestamp */ file_put_contents('sub-poller-last-run.txt', time());
Run Your Script
It's time to test the script and make sure it works. From your shell, run:
[user@host ~/mybot]$ php sub-poller.php
You should see some output indicating "Found a new post: ..." and, assuming your PHP environment is configured to send email, you'll get a new email message about the posts.
Now, immediately run the script again. This time you shouldn't see any output, unless someone happened to make a new post in the brief interval between the two executions of the script.
Scheduling
A script like this isn't very useful unless it runs periodically by itself, so you should probably schedule it. On a Linux system, you can do this by adding a cron job. Here's a sample cron entry to run your script every 5 minutes:
*/5 * * * * (cd ~/mybot && php sub-poller.php >/dev/null)
Don't worry about this being too frequent. Reddit grants you 600 API requests every 10 minutes, and this script only generates one request.
Did you encounter problems?
If Snuze gave you some errors, or if the output wasn't what you were expecting, feel free to visit /r/snuze and ask for help!