"Evernoting" from the command line

I won't get into the argument why Evernote is good or why it's totally useless. For a long time I didn't understand the hype around it but quite recently I have found a very good use to it. Finally I have a centralised location of all my scripts or pieces of code that I use at various places, all the code that I use at work (and have previously collected in various txt scripts scattered all over my laptop). I was working on a few Puppet scripts the other day via a virtual machine and I really wanted to save my scripts to Evernote and of course not by copy-pasting - I wanted a very simple, command line interface that allows me to add an entry to my ever-growing notes.

I found the official Evernote PHP-SDK and an example that made my life much easier - I have essentially extended this and made it - shall we say, "command line compatible". The example script uses EDAM (no, not the Dutch cheese) - Evernote Data Access Management - which, in a nutshell is a protocol to exchange Evernote data with the Evernote service. In the background EDAM is using a technology called Thrift. Thrift - originally developed by Facebook and now hosted by the Apache Software Foundation - is a binary communication protocol that allows the definition and creation of services for a large number of languages.

First of all, before we proceed, please make sure that you get a an Authorisation Token from either https://sandbox.evernote.com/api/DeveloperToken.action or https://www.evernote.com/api/DeveloperToken.action (depending on whether you want to save notes against a sandbox environment for testing purposes or against your real notebook). If you already have a token, prepare it as we'll be using it very soon. Without further to do, let's jump straight in and get coding.

There exist two 'run-modes', if you will, for the script (which I have intuitively named as 'note.php'), a 'cli' mode and a 'file' mode. The 'cli' mode allows you send to notes to Evernote from the command line, that is, whatever you type in the command line will be sent to Evernote whereas the 'file' mode will read the whole context of a file and save that as a note. Both modes accept standard HTML tags, so if you want to highlight something, you can use <strong> for example.

The script accepts 3 arguments:
--mode: either 'cli' or 'file'
--subject: the title of the note
--text: the text or file content to save as a note.

php note.php cli "Test Note" "This is a test note. It accepts HTML tags as well."
php note.php file "Another test" /path/to/your-file.log

And here's the command to execute from your command line:

evernote-note-php-cli-sample

Which results in the following note created in the Evernote web interface:

evernote-blog-testnote-sample

The first section of the code is nothing exciting and it's pretty similar to the original example provided by Evernote. The only difference is that I have added a help function that describes the functionality of this script and it's about time I start discussing the script's functionality.

use EDAM\Types\Data, EDAM\Types\Note;
use EDAM\Error\EDAMUserException, EDAM\Error\EDAMErrorCode;
use Evernote\Client;

require_once 'autoload.php';
require_once 'Evernote/Client.php';
require_once 'packages/Errors/Errors_types.php';
require_once 'packages/Types/Types_types.php';
require_once 'packages/Limits/Limits_constants.php';

function help() {
echo "\nThis is a command line PHP script with the following options:
    Usage:
    " . basename(__FILE__) . " cli|file title \"text\"|\"/path/to/file\"
    title: Title of note
    cli: to be followed by \"text\", e.g:
      " . basename(__FILE__) . " cli \"Note title\" \"Add to note\"
    file: must be followed by a path, e.g.:
      " . basename(__FILE__) . " file \"Another title\" \"/home/user/notes.txt\"

    Both the cli and file options accept HTML tags as parameters, e.g.:
      " . basename(__FILE__) . " cli \"My Title\" \"I can accept HTML tags\"\n
";
}

The real work is then done by a custom function that I've added - note the highlighted line, that' where you need to put your developer access token as mentioned before. Once the authentication is done, we create a new Client object as well as a new Note object, specify the required parameters for the notes (title, content) - bearing in mind that Evernote use their own markup language (ENML) - and finally call the createNote() function to create/save our note:

<?php
function addNote($title, $content) {
    $authToken = "";
    $client = new Client(array('token' => $authToken));
    
    $noteStore = $client->getNoteStore();
    $note = new Note();
    $note->title = $title;
    // The content of an Evernote note is represented using Evernote Markup Language
    // (ENML). The full ENML specification can be found in the Evernote API Overview
    // at http://dev.evernote.com/documentation/cloud/chapters/ENML.php
    $note->content =
        '<?xml version="1.0" encoding="UTF-8"?>' .
        '<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">' .
        '<en-note>' . nl2br($content) . '<br/></en-note>';

    // When note titles are user-generated, it's important to validate them
    $len = strlen($note->title);
    $min = $GLOBALS['EDAM_Limits_Limits_CONSTANTS']['EDAM_NOTE_TITLE_LEN_MIN'];
    $max = $GLOBALS['EDAM_Limits_Limits_CONSTANTS']['EDAM_NOTE_TITLE_LEN_MAX'];
    $pattern = '#' . $GLOBALS['EDAM_Limits_Limits_CONSTANTS']['EDAM_NOTE_TITLE_REGEX'] . '#'; // Add PCRE delimiters
    if ($len < $min || $len > $max || !preg_match($pattern, $note->title)) {
        print "\nInvalid note title: " . $note->title . '\n\n';
        exit(1);
    }
    $createdNote = $noteStore->createNote($note);

    print "Successfully created a new note:  " .  $note->title . " (GUID: " . $createdNote->guid . ")\n";
}
?>

Further to this, I have added a little bit of error checking and logic to make sure that someone who has fat fingers, doesn't do a mistake and add a name of a file as a note instead of actually reading the file:

<?php
if ($argc != 4 || in_array($argv[1], array('--help', '-help', '-h', '-?'))) {
    help();
    exit();
} else {
    $mode = isset($argv[1]) ? $argv[1] : undef;
    $title = isset($argv[2]) ? $argv[2] : undef;
    $content = isset($argv[3]) ? $argv[3] : undef;

    if (!isset($mode) || !isset($title) || !isset($title)) {
        help();
    }

    if ($mode == "cli") {
        addNote($title, $content);
    }
    elseif ($mode == "file") {
        //parse file
        if (!file_exists($content)) {
            echo "The file defined cannot be found - make sure you entered the right file (" . $content . ") and that you're using the right parameter ('file').";
            help();
            exit();
        } else {
            $content = file_get_contents($content);
            addnote($title, $content);
        }
    }
    else {
        help();
        exit();
    }
}
?>

And that's really it. If you'd like to try this out you'll of course need all the Evernote libraries - feel free to check my code out (including all the required files) from GitHub. Happy Evernoting!

Show Comments