Minimum Viable Micropub

"Micropub is an open API standard that is used to create posts on one's own domain using third-party clients. Web apps and native apps (e.g. iPhone, Android) can use Micropub to post short notes, photos, events or other posts to your own site, similar to a Twitter client posting to Twitter.com." (Micropub on Indiewebcamp)

This means I can now publish blog posts to my site using other peoples' posting clients, of which there are several. Previously, I was ftping markdown files to my server, then running a slightly unreliable PHP script to process the queue based on when the files were last updated. Which mostly worked, but when it didn't it was a pain to untangle.

IndieAuth

I wasn't expecting to have a micropub endpoint any time soon because it needs you to be able to sign into your site with IndieAuth. Fortunately, thanks to amazing work of aaronpk and others, most of the legwork has been done here, and you can delegate your IndieAuth; in your site <head>:

<link rel="authorization_endpoint" href="https://indieauth.com/auth" />
<link rel="token_endpoint" href="https://tokens.indieauth.com/token" />

Micropub

Then create a micropub script (eg. micropub.php) and make it discoverable in the same way:

<link rel="micropub" href="https://rhiaro.co.uk/micropub.php" />

Initially I wanted my endpoint at https://rhiaro.co.uk/micropub and set an .htaccess rule to redirect to the PHP script. This doesn't work; POST requests can't follow redirects.

Next, here's a bare minimum PHP script to store things posted to your site with a micropub client. This just dumps the POST request to a text file, which is where I started to see if it would work. What I actually do now is turn posts and metadata into triples and insert them into my triplestore, but you probably don't want to hear about that :)

<?
// Tell client where I can syndicate to
if(isset($_GET['q']) && $_GET['q'] == "syndicate-to"){
    header('Content-type: application/x-www-form-urlencoded');
    echo "syndicate-to[]=twitter.com%2Frhiaro";
    exit;
}

// Check for post
if(!empty($_POST)){
    $headers = apache_request_headers();
    // Check token is valid
    $token = $headers['Authorization'];
    $ch = curl_init("https://tokens.indieauth.com/token");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HTTPHEADER, Array(
         "Content-Type: application/x-www-form-urlencoded"
        ,"Authorization: $token"
    ));
    $response = Array();
    parse_str(curl_exec($ch), $response);
    curl_close($ch);
    // Check for scope=post
    // Check for me=https://rhiaro.co.uk
    $me = $response['me'];
    $iss = $response['issued_by'];
    $client = $response['client_id'];
    $scope = $response['scope'];
    if(empty($response)){
        header("HTTP/1.1 401 Unauthorized");
        exit;
    }elseif($me != "https://rhiaro.co.uk" || $scope != "post"){
        header("HTTP/1.1 403 Forbidden");
        exit;
    // Check that something was posted
    }elseif(empty($_POST['content']){
        header("HTTP/1.1 400 Bad Request");
        echo "Missing content";
    }else{

        // DO YOUR THING HERE
        //  ie. insert post content and metadata into your store, write it to a file, whatever you do to add it to your site.
        // For demonstration purposes, let's dump the POST request into a file and return the URL of the file.

        $fn = "posts/".time().".txt";
        $h = fopen($fn, 'w');
        foreach($_POST as $k => $v){
            $data .= "[$k] => $v<br/>";
        }

        fwrite($h, $data); 
        fclose($h); 

        // Set headers, return location
        header("HTTP/1.1 201 Created");
        header("Location: ".$fn);
    }
}
?>

I got this far by working through the instructions as part of setting up Quill, so that's a good place to start!

🏷 http://vocab.amy.so/blog#Doing http://vocab.amy.so/blog#Doing hacking indieweb slogd php micropub