<?php    /* --- ۞---> text { encoding:utf-8;bom:no;linebreaks:unix;tabs:4sp; } */
                                                    
$plog_editor_ver '0.7.1';
/*
    Plog Editor

    Self-contained editor for plog files, and their data 'pairs'.

    This is one of those scripts that gets hacked together to perform a task,
    and then another task gets bolted on, and then a feature, and so on. It's
    purpose is to view and edit the contents of "plog" files, which are those
    cute wee serialized arrays I seem to use for all sorts of things, but mainly
    tracking referrers.

    Plog editor is geared towards viewing my organic search hits and inward
    links lists, though still retains the basic -/+/del editing features of the
    original (distro machine) code. The contents of these referrer plogs is so
    trivial that editing them seems an unlikely task, though deleting entries is
    highly useful in this context.

    plog-edit improves on the distromachine code, with the ability to handle the
    quirks of URL encoding, as well as getting it all spat out in strict XHTML/
    HTML5. Working links are created from all the URLs, so you can jump there
    directly.

    It's self-contained, and doesn't even rely on plog.php to do its stuff;
    merely access to a folder with some plog files in it. More than likely,
    I'll end up removing the distromachine's own plogging code, and it use this
    as an include().

    To use:

        It's quite simple to operate; set the prefs, and load it in a web
        browser.

        plog-edit throws up a menu of all available plog files, from which you
        can choose the current plog. It accepts $_GET or $_POST variables, so
        you can easily make links in your admin page like so..

            https://mydomain/admin/plog-edit.php?plog=.ht_google.plog

        Note:    You will need to have pajamas installed to use this. aka. 'php
                and javascript advanced MD5 authentication system' get it here..

                    http://corz.org/server/security/pajamas.php

                or else drop in your own auth code, unless you don't need auth,
                for publicly editable plogs; perhaps a rudimentary voting
                system. hmmm..

                If you want all the funky 2-column action, remember to alter the
                location of the css (styles). Grab mine for details of the
                various classes used. Without eadditional CSS, it will still
                function fine, but will look pretty basic.

    Output is paginated HTML5, with cute controls for moving forward and back.

    Have fun!

    ;o) Cor

    foibles:

        If the page size (configurable) is longer than the viewport, the
        navigation controls won't "stick" to the bottom right of the browser
        viewport if you scroll the page on older versions of Internet Explorer -
        plog-edit was designed for admins, who wouldn't be using such browsers.


    (c) copyright corz.org 2005->today

*/


// prefs..
//


// these should be fine as-is..
//
$pe_root $_SERVER['DOCUMENT_ROOT'];
$pe_self $_SERVER['PHP_SELF'];


// Location of WRITABLE plog directory.
// If the plog editor can't make a (temporary) backup, it will NOT allow you to save edits
// use '.' if the plog files are in the same directory as this script.
// If the folder is inside the folder this script is in, use only the name; e.g. "foo".
// or else specify the full path to the folder, including server root.
//
$plog_basedir '.';


// The name of a WRITEABLE folder *inside* the plog folder, for backups..
//
$backupdir '';


// default plog-file to load..
//
$plog '.ht_example.plog';


// some string that is unique to your plog file names (so we can omit other
//files from the drop-down menu). It doesn't have to be a file extension.
//
$plog_identifier '.plog';


// for adding plog entries..
$plogger_location 'plog.php';


// Chop..
//
// Overlong entries will be visually chopped, which preventsyour nice two-column
// layout getting messed up. The chopping is done in a nice way...
//
// http://corz.org/extremely/long/path/to/some/deep/file/called/foo.php
//
// might end up looking like..
//
// http://corz.org/extreme.../foo.php
//
// Of course, this only affect the *view*, not the link itself.
//
//
// Define here the length of start and end sections, in the middle goes " ..."
//
$chop_left 60;
$chop_right 20;


// Items-Per-Page
//
// Too many entries may slow down your page operations.
// Also, non-compliant browsers will scroll the page controls if you have
// to scroll the viewport. But then, maybe not. Enter any numeric value..
//
$per_page 25;

// A menu is now provided for you to choose on-the-fly..

// Menu items for the per-page drop-down. Values under 100 only, please.
// Values over 100 (as well as the total number) will be added automatically.
// Numeric entries, separated with a comma..
//
$per_pages '10,20,25,30,42,64,80';


// Style Sheet Paths. Separate multiple sheets with commas..
$plog_edit['styles'] = '/inc/css/machine.css';



// Authentication
//
$do_authentication false;


// set the above to false to let everyone edit your plogs..


// include auth code, etc..



/*
 If you are not including some site-wide initialization file (as above)
 then you'll need to inser the pajamas code directly into this file,
 perhaps uncomment the following..

// pajamas authentication..
if (isset($do_authentication)) {
    include $site_config['root'].'/blog/inc/pajamas/pajamas.php';
    $auth = new pajamas($_SERVER['HTTP_HOST']);

    // pj module's prefs..
    $auth->_createForms = true;
    $auth->_no_autocomplete = true;
    $auth->_code_location = '/blog/inc/pajamas/modules/client-side/md5.js';
    $auth->_login_password = 'MyP455w0Rd';
}
*/




//
// end prefs



// how we begin..
$page '';
$start 0;
$message '';
$show_session_errors false;

// include plogger for adding plogs..
if (!function_exists('log_pair')) { include $plogger_location; }

// get GET/POST variables..
if (!empty($_REQUEST['plog'])) $plog $_REQUEST['plog'];
$pe_self .= '?plog='.$GLOBALS['plog'];

if (!empty(
$_REQUEST['start'])) $start $_REQUEST['start'];
if (
$start $start 0;

if (!empty(
$_REQUEST['per-page'])) $per_page $_REQUEST['per-page'];

if (!empty(
$_REQUEST['input-plog'])) { log_pair($plog_basedir.'/'.$plog$_REQUEST['input-plog']) ;}

$do_sort_plog false;
if (!empty(
$_REQUEST['plog-sort']) and $_REQUEST['plog-sort'] == 'on'$do_sort_plog true;
if (
$do_sort_plog) {
    
$sort_chk ='checked="checked" ';
    
$sort_val ='on';
} else {
    
$sort_val ='off';
    
$sort_chk ' ';
}

// tag onto requests to retain sorting value..
$sort_add_str '';
if (
$sort_val == 'on') {
    
$sort_add_str '&amp;plog-sort=on';
}


// let's make the page..
echo '<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
<title>plog editor [v'
,$plog_editor_ver,'] .. edit data \'pairs\' from plog files.. by corz.org  [',$plog,']</title>
<meta name="description" content="plog editor for corz.org..enables editing of data \'pairs\'" />'
;

$style_sheets explode(','$GLOBALS['plog_edit']['styles']);
foreach (
$style_sheets as $my_sheet) {
    echo 
'
<link rel="stylesheet" href="'
,$my_sheet,'" type="text/css" media="screen"/>';
}
echo 
'
<style media="screen">
.machine-stats {
    margin-top: 10rem;
}
.plog-input, .per-page, .plog-add { position: fixed; font-size: small;}
.plog-input { top: 1rem; }
.plog-input, .per-page { left: 1rem; }
.per-page { top: 5rem; }
.plog-add {
    right: 1rem;
    top: 1rem;
}
.auth-logout { right: 1rem; }
.left-column { width: 80%; }
.right-column { width: 10%; }
.plogedit-line:hover {
    color: #000000;
    background: #FCDB8D;
    }
</style>
</head>
<body>
<div class="machine-container">
<div class="clear"></div>'
;


echo 
'
<div class="admin">'
;

if (
$do_authentication and !$auth->auth_user()) { // NOT authenticated!

    // spit out a login form..
    
echo $auth->getAuthCode();; // gotta include this first.
    
echo $auth->getLoginForm();
    echo 
'<div class="clear-half"></div>';
    die(
"</div>\n</body>\n</html>\n");

} else {

    
$plog_file $plog_basedir.'/'.$plog;

    if (isset(
$_GET['del'])) {
        
delete_plog($plog_filedo_slashes($_GET['del']), $backupdir);

    } elseif (isset(
$_GET['edit'])) {
        
edit_plogs($plog_file$_GET['edit'], do_slashes($_GET['file']), $backupdir);

    } else {
        echo 
'
    <h2 class="machine-messages">plog: '
,$plog,'..</h2>';

    }


    
// plog selection menu..
    //
    
echo '
    <form id="form-plog-input" method="get" action="'
,$pe_self,'">
    <div class="plog-input">
        <select name="plog">'
;

    
$filenames return_dir($plog_basedir);
    
asort($filenames);
    foreach (
$filenames as $this_file) {
        
$selected '';
        if (
strstr($this_file$plog_identifier)) {
            if (
$this_file == $plog$selected ' selected';
            echo 
'
            <option value="'
,$this_file,'"',$selected,'>',$this_file,'</option>';
        }
    }
    echo 
'
        </select>
        <input type="submit" value="load" title="get it fresh" />
        <input type="hidden" name="per-page" value="'
,$per_page,'"/>
        <input type="hidden" name="plog-sort" value="'
,$sort_val,'"/>
    </div>
    </form>'
;


    
/*
    do stats..    */

    
$total_items splurge_plog($plog_file$do_sort_plog);

    
// if we deleted an item, but were paginated at "all", remain at "all", by subracting 1 from the total..
    
if ($per_page == $total_items 1) { $per_page -= ;}
    echo 
'
<div class="machine-stats-link">
    <a href="'
,$pe_self,'&amp;start=0&amp;per-page=',$per_page,$sort_add_str,'" title="load the first page"><strong>|&bull;</strong></a> ';
    if (
$start 1) {
        echo 
'
    <a href="'
,$pe_self,'&amp;start=',$start-$per_page,'&amp;per-page=',$per_page,$sort_add_str,'" title="load the previous page"><strong>««</strong></a> ';
    } else {
        echo 
'<strong> «« </strong>';
    }
    echo 
'
    <a href="'
,$pe_self,'&amp;start=',$start,'&amp;per-page=',$per_page,$sort_add_str,'" title="refresh this page without editing anything"><strong>«&bull;»</strong></a> ';
    if (
$start <= $total_items-$per_page) {
        echo 
'
    <a href="'
,$pe_self,'&amp;start=',$start+$per_page,'&amp;per-page=',$per_page,$sort_add_str,'" title="load the next page"><strong>»»</strong></a> ';
    } else {
        echo 
'<strong> »» </strong>';
    }
    echo 
'
    <a href="'
,$pe_self,'&amp;start=',$total_items-$per_page+1,'&amp;per-page=',$per_page,$sort_add_str,'" title="load the last page [ total: ',$total_items,' ]"><strong>&bull;|</strong></a>';
    echo 
'
</div>'
;


    
// entries-per-page menu (do it after we know the total number of items..
    //
    
echo '
    <form id="form-per-page" method="get" action="'
,$pe_self,'">
    <div class="per-page">
        <select name="per-page">'
;

    
// we re-use their variable name for the array..
    
$per_pages explode(","$per_pages);

    
// add "total items" to the array
    //$per_pages = array_merge(array($total_items), $per_pages); // cute! but best to put this after the list..

    
$w_x 100;
    while (
$w_x $total_items) {
        
$per_pages[] = $w_x;    // push
        
$w_x += 100;
    }

    
// add "total items" to the array (less cute, but easy)..
    
if ($total_items end($per_pages)) { $per_pages[] = $total_items; }

    foreach (
$per_pages as $pernum) {
        
$selected '';
        if (
$pernum == $per_page$selected ' selected';
        echo 
'
        <option value="'
,$pernum,'"',$selected,'>',$pernum,'</option>';

    }

    echo 
'
        </select>
        <input type="checkbox" name="plog-sort" id="sort" '
,$sort_chk,'/>
        <label for="sort">sort by scores &nbsp; </label>
        <input type="submit" value="paginate" title="Go!" /><br />
        <input type="hidden" name="plog" value="'
,$plog,'"/>
    </div>
    </form>'
;


// plog creation..
//
if (function_exists('log_pair')) {
    echo 
'
<form id="form-plog-add" method="post" action="'
,$pe_self,'">
<div class="plog-add">
    <input type="text" size="32" id="input-plog-add" name="input-plog" />'
;
    echo 
'
    <input type="submit" value="add" title="add a plog!" />
    <input type="hidden" name="plog" value="'
,$plog,'"/>
</div>
</form>
<div class="clear-small"></div>'
;
}
    
// do a logout button..
    
if ($do_authentication) { echo $auth->getLogoutButton(); }
    die(
'
</div>
<div class="clear-small"></div>
</body>
</html>'
);

}

if (!empty(
$GLOBALS['do_debug'])) { debug('out'); }// :debug:


// trim slashes from a string, or else don't..
function do_slashes($string) {
    if (
get_magic_quotes_gpc()) {
        return 
trim(stripslashes($string));
    } else {
        return 
trim($string);
    }
}


/*
    function grab_plog()

    returns the raw serialised array from a plog score file

    pass the 2nd parameter as true, to get back the array()
    unserialized.

                                                    */
function grab_plog($plog_file$unserialize=false) {

    if (
is_readable($plog_file)) {
        
$grab fopen($plog_file'rb');
        
$lock flock($grabLOCK_SH);
        if (
$lock) {
            
$scores_data = @fread($grab, @filesize($plog_file));
            
$lock flock($grabLOCK_UN);
        }
        
fclose($grab);
        
clearstatcache();
    }

    if (
$unserialize) {
        
$plog_array = @unserialize($scores_data);
        if (
is_array($plog_array)) {
            return 
$plog_array;
        }
    }

    return 
$scores_data;


}
/*
end function grab_plog()    */



/*
    show plog, with editing/reviewing knobs on..
                                                        */
function splurge_plog($plog_file$sort_order="total") {

    
$pe_self $GLOBALS['pe_self'];
    
$count 0;

    
// logout button..
    
echo '
<!--plogs plog plogs ... -->
<script>
function del(file,go) {
    if ( confirm("\nreally remove " + file + " from list?\n") ) window.location = go;
}
function edit(file,go) {
    var escore=prompt("enter the new score for " + file + "..","");
    window.location = go + "&score=" + escore;
}
</script>
<noscript><!-- JavaScript Required --></noscript>'
;


    if (
file_exists($plog_file)) {

        
$all_plogs grab_plog($plog_file);
        if (!empty(
$all_plogs)) {

            
$plog_array = @unserialize($all_plogs);

            if (!
is_array($plog_array)) {
                echo 
'
    <div class="machine-stats"><h2>not a plog file!</h2></div>'
;
                return 
false;
            }

/*
    I realize that all this double-encoding seems totally barmy, but this enables
    us to pass xhtml-compliant, encoded URL's through the JavaScript functions
    and have them still FUNCTION at the other end of a $_REQUEST. Foreign language
    characters remain intact, and parameters within URLs, won't be sent as actual
    parameters; messing up the whole show. Works great.

    In other words, you can safely edit/delete/display links like this..

        http://he.wikipedia.org/wiki/צניעות
    or..
        http://search.aol.co.uk/aol/search?query=foo+bar&cr=foo&lr=bar&SearchBar=foo
*/
            
echo '
    <div class="machine-stats">'
;

            
// full sorting is currently not implemented, and will require
            // multi-dimensional arrays to be stored within the plog.
            // however, for now, you can set this to false, and get back
            // the array in the order it was built, in other words, newest
            // entries first ?
            //
            
switch ($sort_order) {
                case 
false:
                    break;
                default: 
// 'total' or something else    // sort by total downloads
                    
arsort($plog_array);
                    break;
            }

            while (list(
$key$val) = each($plog_array)) {
                if (
$count >= $GLOBALS['start'] and $count <= ($GLOBALS['start']+$GLOBALS['per_page'])) {
                    echo 
'
        <div class="plogedit-line">'
;

                
$display htmlentities(title_chop($key$GLOBALS['chop_left'], $GLOBALS['chop_right']));
                
//$key = htmlentities($key);  addslashes($key); quotemeta($key);
                    
echo "
        <div class=\"left-column\">"
;
                    echo 
hit_link($key$plog_file);
                    echo 
"
            <small><a href=\"javascript:del('"
,htmlentities(rawurlencode($key)),"','",$pe_self,"&amp;del="
            
,htmlentities(urlencode(htmlentities(rawurlencode($key)))),"&amp;start=",$GLOBALS['start'],'&amp;per-page=',$GLOBALS['per_page'],$GLOBALS['sort_add_str'],"')\" title=\"REMOVE ",
                
htmlentities($key)," from list\">",$display,"</a></small>";

                    echo 
'
        </div>
        <div class="right">
            <a href="'
,$pe_self,'&amp;file=',htmlentities(rawurlencode($key)),'&amp;edit=down&amp;start=',$GLOBALS['start'],'&amp;per-page=',$GLOBALS['per_page'],$GLOBALS['sort_add_str'],'"
            title="decrease '
,htmlentities($key),'\'s score by one"> <strong>-</strong></a> &nbsp;';

                    echo 
"
            <a href=\"javascript:edit('"
,htmlentities(rawurlencode($key)),"','",$pe_self,
            
"&amp;stats=true&amp;edit=score&amp;&amp;start=",$GLOBALS['start'],"&amp;file=",htmlentities(urlencode(htmlentities(rawurlencode($key)))),'&amp;per-page=',$GLOBALS['per_page'],$GLOBALS['sort_add_str'],"')\" title=\"edit score for \n",
                
htmlentities(rawurlencode($key)),"\">",$plog_array[$key],"</a>";

                    echo 
'
            <a href="'
.$pe_self.'&amp;file=',htmlentities(rawurlencode($key)),'&amp;edit=up&amp;start=',$GLOBALS['start'],'&amp;per-page=',$GLOBALS['per_page'],$GLOBALS['sort_add_str'],'"
            title="increase '
,htmlentities($key),'\'s score by one"><strong>+</strong></a>
        </div>
        <div class="clear"></div>
        </div>'
;
                }
                
$count += 1;
            }
            echo 
'
    </div>'
;
        }
    } else {
        echo 
'<div class="warning centered">plog file [',$plog_file,'] is missing</div>';
    }
    echo 
'
</div>'
;
    return 
$count-1;
}


/*
    takes a long string a chops it in a "nice" way, removing the middle part
    so both ends are still legible. you can define the maximum length of both
    parts of the string. The middle section is replaced with "..."..
*/
function title_chop($tring$startlen=64$endlen=32) {
    if (
strlen($tring) > ($startlen $endlen)) {
        
$tring substr($tring0$startlen).'...'.substr($tring, -$endlen);
    }
    return 
$tring;
}




// if the plog is a link, or a search hit, make an anchor for it..
function hit_link($string$plog_file='') {

    
$make_link false;
    if (
substr($string07) == 'http://') {
        
$href =  str_replace(" "'%20;'$string);
        
$make_link true;
    } else {
        switch (
true) {
            case 
stristr($plog_file'google'):
                
$href 'http://www.google.com/search?q='.rawurlencode($string);
                
$make_link true;
                break;
            case 
stristr($plog_file'yahoo'):
                
$href 'http://search.yahoo.com/search?p='.rawurlencode($string);
                
$make_link true;
                break;
            case 
stristr($plog_file'live'):
                
$href 'http://search.live.com/results.aspx?q='.rawurlencode($string);
                
$make_link true;
                break;
            break;
        }
    }

    if (
$make_link) {
        return 
'<a href="'.htmlentities($href).
    
'" title="Go there now! (drag into an empty tab to NOT send referrer information)">go!</a>';
    }
}



/*
    delete stat..
                                        */
function delete_plog($plog_file$entry$backupdir='_arc') {

    if (
file_exists($plog_file)) {

        
$all_plogs grab_plog($plog_file);

        if (!empty(
$all_plogs)) {
            
$plog_array unserialize($all_plogs);

            if (
array_key_exists($entry$plog_array)) {
                unset(
$plog_array[$entry]);

                
// write the updated plog..
                
$sa serialize($plog_array);
                
write_plogs($plog_file$sa$backupdir);
                echo 
'<span class="machine-messages">'urldecode($entry),' <strong>deleted</strong> from list</span>';
            }
        }
    }
}




/*
    function write_plogs()
    write a serialized array (string data) to a file

*/
function write_plogs($plog_file$data$backupdir='_arc') {

    if (empty(
$data)) return;

    if (
stristr($backupdir'/')) { $backupdir str_replace('/''');}

    
$bax $GLOBALS['plog_basedir'].'/'.$backupdir.'/'.$GLOBALS['plog'].'_bax';

    if (!
file_exists($GLOBALS['plog_basedir'].'/'.$backupdir)) { mkdir($GLOBALS['plog_basedir'].'/'.$backupdir); }

    if (!
file_exists($bax) or (file_exists($bax) and (filesize($plog_file) != 0))) { // or else compare+say, 100 bytes
        
@copy($plog_file$bax); // will overwrite
    
}

    
$fp = @fopen($plog_file'w');
    if (
is_writable($plog_file)) {
    
$lock flock($fpLOCK_EX);

        if (
$lock) {
            
fwrite($fp$data);
            
flock ($fpLOCK_UN);
        }
        
fclose($fp);
        
clearstatcache();
        return (
1);
    }
}
/*
end function write_plogs()    */




/*
    edit plogs..
                                            */
function edit_plogs($plog_file$edit$file$backupdir='_arc') {

    if (
file_exists($plog_file)) {

        
$all_plogs grab_plog($plog_file);

        if (!empty(
$all_plogs)) {
            
$plog_array unserialize($all_plogs);

            if (
array_key_exists($file$plog_array)) {

                if (
$edit == 'up') {
                    
$plog_array[$file]++;
                    
$edit_notice '<span class="machine-messages">'.urldecode($file).' counter <strong>plus</strong> one</span>';
                }

                if (
$edit == 'down') {
                    
$plog_array[$file]--;
                    
$edit_notice '<span class="machine-messages">'.urldecode($file).' counter <strong>minus</strong> one</span>';

                    if (
$plog_array[$file] < 0) {
                        
$plog_array[$file] = 0;
                        
$edit_notice '<span class="machine-messages">'.urldecode($file).' is <strong>already at zero!</strong></span>';
                    }
                }

                if (
$edit == 'score') {
                    
$new_score = @$_GET['score'];
                    if (
is_numeric($new_score)) {
                        if (
$new_score 0) {
                            
$plog_array[$file] = $new_score;
                        } elseif (
$new_score == 0) {
                            
$plog_array[$file] = 0;
                        }
                    } else {
                        
$new_score '<span class"machine-blink">illegal value</span>';
                    }
                    
$edit_notice '<span class="machine-messages">'.urldecode($file).' counter <strong>edited</strong> to <strong>'.$new_score.'</strong></span>';
                }
                echo 
$edit_notice;
            }

            
// write the updated score file
            
$sa serialize($plog_array);
            
write_plogs($plog_file$sa$backupdir);
        }
    }
}
/*
end function edit_plogs()    */


/*
return a list of files in a folder
as an array of file names..
                              */
function return_dir($plog_dir) {

    if (
$the_plog = @opendir($plog_dir)) {

        
$q 0;
        while (
false !== ($file readdir($the_plog))) $itemz[] = $file;

        
// now we have all the files in one array
        
closedir($the_plog);
        if (!empty(
$itemz)) { return $itemz; } else { return false; }

    } else {
        
// couldn't open the dir..
        
return false;
    }
}


/*

    changes:

        0.6    You can now enable/disable the sort-by-totals, which in theory
            should get you your plog in the exact order it was built. This
            is handy for knowing which were the most recent hits/entries.

        0.5    You can now choose the items-per-page on-the-fly, from a drop-
            down menu. You can also configure the menu items - the larger
            values, as well as the total value, are calculated automatically,
            though I figured you might like to set the smaller values, to fit
            your browser viewport.

        0.4    plog edit will now return to the same page of results after an
            add/subtract/delete/edit operation, rather than return to the
            first page.

        0.3 added better controls for pagination, and some other stuff.
*/

?>
back to the source menu
downloadtest

Welcome to corz.org!

If something isn't working, I'm probably improving it, try again in a minute. If it's still not working, please mail me!