Skip to content

Commit

Permalink
Initial checkin
Browse files Browse the repository at this point in the history
  • Loading branch information
ianbarber committed May 17, 2012
0 parents commit 419f543
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 0 deletions.
9 changes: 9 additions & 0 deletions LICENSE
@@ -0,0 +1,9 @@
Copyright (c) 2012, Ian Barber
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 changes: 32 additions & 0 deletions README.md
@@ -0,0 +1,32 @@
A [YouRLs](http://yourls.org/) plugin to queue clicks to Amazon SimpleDB before processing. This allows using a regular MySQL store even in the face of a high frequency of writes, without concern of connection limit overflow. Clicks are inserted later into the database via an import job.

Install
=======

Ensure that the AWS PHP Client is installed: http://aws.amazon.com/sdkforphp/

To install the plugin itself copy the plugins/sdblog folder to your plugins folder (usually user/plugins).

Configuration
=======

To access SimpleDB you will need to include your AWS key and secret key, available from the AWS console. These should be defined in your YouRLs config.php

define('AWS_KEY', 'KEY_GOES_HERE');
define('AWS_SECRET_KEY', 'SECRET_KEY_HERE');

You can additionally define the region to run in and the domain (database name) for SimpleDB with the following parameters:

define('SDB_REGION', AmazonSDB::REGION_EU_W1);
define('SDB_DOMAIN', 'myqueuetable');

Usage
======

The plugin will automatically shunt clicks onto a SimpleDB call. At appropriate points you are
required to run the import.php script in order to pull the click data into the main YouRLS database
for use in generating statistics. This can be done from a cron script, for example

*/5 * * * * php /var/www/user/plugins/sdblog/import.php 2>&1 /dev/null

The timing of the script will depend on your need for accuracy in statistics versus tolerance for database writes.
Binary file added plugins/.DS_Store
Binary file not shown.
80 changes: 80 additions & 0 deletions plugins/sdblog/import.php
@@ -0,0 +1,80 @@
<?php
chdir(dirname(__FILE__));

define('SDB_IMPORTER', true);
require_once( dirname(__FILE__).'/../../../includes/load-yourls.php' );
require_once( dirname(__FILE__).'/plugin.php' );

global $ydb;
$sdb = sdblog_get_database();
$select = "SELECT * FROM `" . SDB_DOMAIN . "`";
$next_token = null;
$count = 0;
$id_holder = array();
$currId = 0;

// Insert all log message - we're assuming input filtering happened earlier
$query = array();
$clicks = array();

do {
if($next_token) {
$response = $sdb->select($select, array('NextToken' => $next_token));
} else {
$response = $sdb->select($select);
}
foreach($response->body->SelectResult->Item as $item) {
$count++;
$id_holder[$currId][(string)$item->Name] = null;
if($count % 25 == 0) {
$currId++;
$id_holder[$currId] = array();
}
$value = array();
foreach($item->Attribute as $attrib) {
$value[(string)$attrib->Name] = (string)$attrib->Value;
}

$query[] = "(FROM_UNIXTIME(" . $value['time'] . "), '" .
$value['keyword'] . "', '" .
$value['referer'] . "', '" .
$value['ua'] . "', '" .
$value['ip'] . "', '" .
yourls_geo_ip_to_countrycode($value['ip']) . "')";

if(!isset($clicks[$value['keyword']])) {
$clicks[$value['keyword']] = 0;
}
$clicks[$value['keyword']]++;
}

$next_token = isset($response->body->SelectResult->NextToken) ?
(string) $response->body->SelectResult->NextToken :
null;
} while($next_token);

$q = "INSERT INTO `" . YOURLS_DB_TABLE_LOG . "`
(click_time, shorturl, referrer, user_agent, ip_address, country_code)
VALUES " . implode(",", $query);
$ydb->query($q);


foreach($clicks as $keyword => $click_count) {
$ydb->query('UPDATE ' . YOURLS_DB_TABLE_URL . ' SET clicks = clicks + ' . $click_count . ' WHERE keyword = \'' . $keyword . '\'');
}

if($count == 0 ) {
die("No clicks\n");
}

echo "Inserted $count Clicks\n";

$deleted = 0;
foreach($id_holder as $ids) {
if(count($ids) > 0 ) {
$deleted += count($ids);
$response = $sdb->batch_delete_attributes(SDB_DOMAIN, $ids);
}
}

echo "Deleted $deleted Clicks\n";
93 changes: 93 additions & 0 deletions plugins/sdblog/plugin.php
@@ -0,0 +1,93 @@
<?php
/*
Plugin Name: SimpleDB Logging
Plugin URI: http://virgingroupdigital.wordpress.com
Description: Pushes log updates to Amazon SimpleDB
Version: 0.1
Author: Ian Barber <ian.barber@gmail.com>
Author URI: http://phpir.com/
*/
include_once 'AWSSDKforPHP/sdk.class.php';

if( !class_exists( 'AmazonSDB' ) ) {
yourls_die( 'This plugin requires with AWS SDK for PHP: http://aws.amazon.com/sdkforphp/' );
}

if(!defined('AWS_KEY') || !defined('AWS_SECRET_KEY')) {
yourls_die( 'This plugin requires an amazon key. Define AWS_KEY and AWS_SECRET_KEY in your config.php' );
}

/* Set this in config.php to use a specific region */
if(!defined('SDB_REGION')) {
define("SDB_REGION", false);
}

/* Can override the database name in SDB */
if(!defined('SDB_DOMAIN')) {
define('SDB_DOMAIN', 'yourlslog');
}

yourls_add_filter( 'shunt_update_clicks', 'sdblog_shunt_update_clicks' );
yourls_add_filter( 'shunt_log_redirect', 'sdblog_shunt_log_redirect' );
yourls_add_filter( 'activated_plugin', 'sdblog_plugin_activate' );

/**
* Activate the plugin by creating the SimpleDB queue.
*
* @return void
**/
function sdblog_plugin_activate()
{
$sdb = sdblog_get_database();

$response = $sdb->create_domain(SDB_DOMAIN);
if(!$response->isOK()) {
yourls_die( 'Could not create domain for SimpleDB logging' );
}
}

/**
* Skip click updating - that will be processed out of the queue
*
* @return bool
**/
function sdblog_shunt_update_clicks($false, $keyword)
{
return true;
}


/**
* Log clicks to SimpleDB
*
* @return bool
**/
function sdblog_shunt_log_redirect($false, $keyword)
{
$sdb = sdblog_get_database();
$values = array(
'keyword' => yourls_sanitize_string( $keyword ),
'referer' => ( isset( $_SERVER['HTTP_REFERER'] ) ? yourls_sanitize_url( $_SERVER['HTTP_REFERER'] ) : 'direct' ),
'ua' => yourls_get_user_agent(),
'ip' => yourls_get_IP(),
'time' => time()
);

$response = $sdb->put_attributes(SDB_DOMAIN, uniqid(), $values);

return true;
}

/**
* Return the SimpleDB object
*
* @return AmazonSDB
**/
function sdblog_get_database()
{
$sdb = new AmazonSDB();
if(defined('SDB_REGION') && SDB_REGION) {
$sdb->set_region(SDB_REGION);
}
return $sdb;
}

0 comments on commit 419f543

Please sign in to comment.