The Wayback Machine - http://web.archive.org/web/20050428080734/http://www.pastebin.com:80/pastebin.php?showsource=php
<?php
/******************************************************************************

PHP Code Pastebin
=================

This tool was designed to enable collaborative code review via the #php IRC
channel. Inspired by www.parseerror.com/paste, but more streamlined and
capable of allowing collabation via IRC by allowing easy modification of
posted code. Another benefit is short urls - http://pastebin.com/333

You can do whatever you want with this code, but if you have fixes or
feature suggestions, please send them to paul@elphin.com or catch me on IRC
(LordElph on EFNet #php)

The latest version of this code can always be found at http://pastebin.com

The code has been purposely designed as a single file so that the source is
easily viewable.

History
=======
v0.24 - 26-May-04 - finally added tab key support within textarea
                    (suggested by Droll a year ago!). Also removed the
                    80 col word wrapping
v0.23 - 02-Mar-03 - add Postgres support (thanks Tim Hunter) and a few
                    configuration options to make "non php" pastebins
                    easy to set up.
v0.22 - 01-Feb-03 - minor tweaks to maintain xhtml compliance
v0.21 - 23-Jan-03 - prevented more mischief with long poster names
v0.20 - 22-Jan-03 - heuristic keyword hyperlinking to php manual
v0.12 - 19-Jan-03 - stripped html tags from poster name
v0.11 - 14-Jan-03 - textarea entity encoding bug fix (thanks Greedo)
v0.1  - 04-Sep-02 - First version

ToDo
====
- highlight diffs between code revisions
- add a 'view full screen' option

Requirements:
=============
This code has no other file dependancies aside from a css stylesheet.

- PHP 4.1 or higher (works with register-globals off)
- MySQL database with following table

    create table pastebin
    (
        pid int auto_increment not null,
        poster varchar(24),
        posted datetime,
        code text,
        parent_pid int default '0',
        primary key(pid)
    );

- Postgres is also supported with the following table definition

    create table pastebin
    (
        pid int DEFAULT nextval('pastebin_pid_seq'::text) not null,
        poster varchar(64),
        posted datetime,
        code text,
        parent_pid int default '0',
        primary key(pid)
    );
    create sequence pastebin_pid_seq;

- For short url generation, Apache with mod_rewrite available. Something
  like the following configuration options should be used

    RewriteEngine on
    RewriteRule /([0-9]+) /pastebin.php?show=$1

  If mod_rewrite is not available, modify the shorturl() function to
  generate 'normal' urls.

******************************************************************************/


///////////////////////////////////////////////////////////////////////////////
// Configuration
//

//----------------------------------------------------------------------------
//site title
$title="php pastebin - collaborative irc debugging";

//----------------------------------------------------------------------------
//database type - either mysql or postgres
$dbsystem="mysql";

//----------------------------------------------------------------------------
//database location, name and credentials...
$dbhost="*****";
$dbname="*****";
$dbuser="*****";
$dbpass="*****";

//----------------------------------------------------------------------------
//format of urls to pastebin entries - %d is the placeholder for
//the entry id.

//  1. for shortest possible url generation in conjuction with mod_rewrite:
$url_format="/%d";

//  2. if using pastebin with mod_rewrite, but within a subdir, you'd use
//     something like this:
//  $url_format="/mysubdir/%d";

//  3. if not using mod_rewrite, you'll need something more like this:
//  $url_format="/pastebin.php?show=%d";


//----------------------------------------------------------------------------
//syntax highlighter can be either "php" or "none" - choose none if you aren't
//use this for php code
$syntax_highlighter="php";


//----------------------------------------------------------------------------
//because we use mod_rewrite to create very short urls,
//we can't rely on PHP_THIS to get our script name
$this_script="/pastebin.php";

//----------------------------------------------------------------------------
//what's the maximum number of posts we want to keep?
$max_posts=50;


///////////////////////////////////////////////////////////////////////////////
// DB base class defines the minimum operations we need here. You can support
// different dbs by writing a new derived class

class DB
{
    var
$row;
    
    function
DB($sql="")
    {
        if (
strlen($sql))
            
$this->query($sql);
    }

    function
f($field)
    {
        return
$this->row[$field];
    }
    
    
//these methods must be overrided by derived classes
    
function query($sql) { return false; }
    function
get_insert_id() { return 0; }
    function
next_record() { return false; }
    function
get_db_error() {return "";}
    
}

///////////////////////////////////////////////////////////////////////////////
// MySQL database support

class DB_mysql extends DB
{
    var
$dblink;
    var
$dbresult;
    
    function
DB_mysql($sql="")
    {
        
$this->dblink=mysql_pconnect(
            
$GLOBALS["dbhost"],
            
$GLOBALS["dbuser"],
            
$GLOBALS["dbpass"])
            or die(
"Unable to connect to database");
    
        
mysql_select_db($GLOBALS["dbname"], $this->dblink)
            or die(
"Unable to select database {$GLOBALS[dbname]}");
    
        
$this->DB($sql);
    }
    
    function
query($sql)
    {
        
$this->dbresult=mysql_query($sql, $this->dblink);
        if (!
$this->dbresult)
        {
            die(
"Query failure: ".mysql_error()."<br />$sql");
        }
        return
$this->dbresult;
    }
    
    function
get_insert_id()
    {
        return
mysql_insert_id($this->dblink);
    }
        
    
    function
next_record()
    {
        
$this->row=mysql_fetch_array($this->dbresult);
        return
$this->row!=FALSE;
    }
    
    function
get_db_error()
    {
        return
mysql_last_error();
    }
}


///////////////////////////////////////////////////////////////////////////////
// Postgres database support (provided by Tim Hunter)
//
/*

//more work required to make PostGres work, feel free to submit a patch


class DB_postgres extends DB
{
    var $dblink;
    var $dbresult;

    function DB_postgres($sql="")
    {
           $this->dblink=pg_connect(
              "host=$GLOBALS[dbhost] ".
              "dbname=$GLOBALS[dbname] ".
              "user=$GLOBALS[dbuser] ".
              "password=$GLOBALS[dbpass]")
            or die("Unable to connect to database");
     
        $this->DB($sql);
    }

    function query($sql)
    {
        $this->dbresult=pg_exec($sql);
        if (!$this->dbresult)
        {
            die("Query failure: ".$this->get_db_error()."<br />$sql<br />");
        }
        return $this->dbresult;
    }

    function get_insert_id()
    {
        $sql = "select currval('pastebin_pid_seq')";
        $result =  pg_fetch_array($this->query($sql));
        return $result[0];
    }

    function next_record()
    {
        $this->row=pg_fetch_array($this->dbresult);
        return $this->row!=FALSE;
    }

    function get_db_error()
    {
        return pg_last_error();
    }
}
*/

///////////////////////////////////////////////////////////////////////////////
// syntax highlighers
//

//simple syntax hilighter and base class for extended ones
class SyntaxHighlighter_none
{
    
//highlight for viewing
    
function highlight($text)
    {
        return
"<code>".nl2br(htmlentities($text))."</code>";
    }

    
//preprocess input before db storage
    
function preprocess($text)
    {
        return
$text;
    }
}

//php syntax highlighter
class SyntaxHighlighter_php extends SyntaxHighlighter_none
{

    function
highlight($php)
    {
        
//get php to do the hard work
        
ob_start();
        @
highlight_string($php);
        
$code = ob_get_contents();
        
ob_end_clean();

        
// Hyperlink keywords - we could have a table or array or
        // interesting keywords, but that would be a bit laborious.
        // Instead, we just for things that look like function calls...
        // this has the downside that it links
        // user defined functions too, but what the hell. It's only
        // a few lines of code....

        
$keycol=ini_get("highlight.keyword");
        
$manual="http://www.php.net/manual-lookup.php?lang=en&amp;pattern=";

        
$code=preg_replace(
            
//match a highlighted keyword
            
'{([\w_]+)(\s*</font>)'.
            
//followed by a bracket
            
'(\s*<font\s+color="'.$keycol.'">\s*\()}m',
            
//and replace with manual hyperlink
            
'<a class="code" title="View manual page for $1" href="'.$manual.'$1">$1</a>$2$3', $code);

        return
$code;
    }

    function
preprocess($code)
    {
        
//ensure code has begin and end tags somewhere
        
$code = trim($code);
        if (
strpos($code, '<?') === false)
            
$code = "<?php\n".$code;
        if (
strpos($code, '?>') === false)
        
$code .= "\n?>";

        return
$code;
    }
}

///////////////////////////////////////////////////////////////////////////////
// global functions
//
function smart_addslashes($str)
{
    if (
get_magic_quotes_gpc())
        return
$str;
    else
        return
addslashes($str);
}


function
shorturl($id)
{
    return
sprintf("http://$_SERVER[HTTP_HOST]".$GLOBALS["url_format"], $id);
}


///////////////////////////////////////////////////////////////////////////////
// global variables
//
$dbclass="DB_".$dbsystem;
$db=new $dbclass;    


///////////////////////////////////////////////////////////////////////////////
// garbage collection
//
// 5% chance of trigging garbage collection - remove the oldest posts
// leaving most recent 50 posts remaining

if(rand()%100 < 5)
{
    
$db->query("select count(*) as cnt from pastebin");    
    if(
$db->next_record())
    {
        
$delete_count=$db->f("cnt")-$max_posts;
        if (
$delete_count>0)
        {
            
//build a one-shot statement to delete old posts
            
$sql="delete from pastebin where pid in (";
            
$sep="";
            
$db->query("select * from pastebin order by posted asc limit $delete_count");
            while (
$db->next_record())
            {
                
$sql.=$sep.$db->f("pid");
                
$sep=",";
            }
            
$sql.=")";
            
            
//delete extra posts
            
$db->query($sql);
        }
    }
}


///////////////////////////////////////////////////////////////////////////////
// process new posting
//
$errors=array();
if (isset(
$_POST["paste"]))
{
    
    
//set/clear the persistName cookie
    
if ($_POST["remember"])
    {
        
//set cookie if not set
        
if (!isset($_COOKIE["persistName"]))
            
setcookie ("persistName", $_POST["poster"], time()+3600*24*365);  
    }
    else
    {
        
//clear cookie if set
        
if (isset($_COOKIE["persistName"]))
            
setcookie ("persistName", "", 0);
    }
    
    if (
strlen($_POST["code2"]))
    {
        
$poster=strip_tags($_POST["poster"]);
        if (
strlen($poster)==0)
            
$poster="Anonymous";
        
        
//wrap the code at 80 columns - this is how it looked in the textarea
        //and ensures we keep a nice layout on the page
        //$code = wordwrap($_POST["code"], 80, "\n", 1);
        
        //use syntax highlighter to preprocess input...
        
$hclass="SyntaxHighlighter_".$syntax_highlighter;
        
$highlighter=new $hclass;
        
$code=$highlighter->preprocess($code2);
        
        
//now insert..
        
$parent_pid=0;
        if (isset(
$_POST["parent_pid"]))
            
$parent_pid=intval($_POST["parent_pid"]);
            
        
$sql="insert into pastebin (poster, posted, code, parent_pid) values (".
            
"'".smart_addslashes($poster)."',".
            
"now(),".
            
"'".smart_addslashes($code)."',".
            
"$parent_pid".
            
");";
            
        
$db->query($sql);    
        
$id=$db->get_insert_id();
        
        
//now redirect, making refresh easier
        
header("Location:".shorturl($id));
    }
    else
    {
        
$errors[]="No code specified";
    }
}


///////////////////////////////////////////////////////////////////////////////
// view source code
//
if (isset($_GET["showsource"]))
{
    switch(
$_GET["showsource"])
    {
        case
"php":    
            
$script=$_SERVER["SCRIPT_FILENAME"];
            
$fp=fopen($script,"r");
            
$contents=fread($fp, filesize($script));
            
fclose($fp);

            
//remove passwords
            
$contents=preg_replace('{(\\$db....)=".*?";}',
                
'$1="*****";', $contents);
            
            
$highlighter=new SyntaxHighlighter_php;
            
$contents=$highlighter->highlight($contents);
        
            
//hyperlink css
            
$contents=str_replace('pastebin.css',
                
'<a href="pastebin.php?showsource=css">pastebin.css</a>',
                
$contents);
                
            echo
$contents;
            break;
        case
"css":    
            
$css=str_replace(".php", ".css", $_SERVER["SCRIPT_FILENAME"]);
            
$fp=fopen($css,"r");
            
$contents=fread($fp, filesize($css));
            
fclose($fp);

            
$highlighter=new SyntaxHighlighter_none;
            echo
$highlighter->highlight($contents);
        
            break;
    }
    
    exit;
}


///////////////////////////////////////////////////////////////////////////////
// HTML page output
//

echo "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n";
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title><?php echo $title ?></title>
<link rel="stylesheet" type="text/css" media="screen" href="pastebin.css" />
</head>


<body>

<p style="display: none;">This site is developed to XHTML and CSS2 W3C standards.  
If you see this paragraph, your browser does not support those standards and you
need to upgrade.  Visit <a href="http://www.webstandards.org/upgrade/" target="_blank">WaSP</a>
for a variety of options.</p>

<div id="titlebar"><?php echo $title ?>
<a href="<?php echo $this_script ?>?showsource=php" class="alt">view php source</a>
</div>
<?php


///////////////////////////////////////////////////////////////////////////////
// recent posts listing
//
$limit="limit 10";
if (isset(
$_REQUEST["list"]))
{
    if (
$_REQUEST["list"]=="all")
        
$limit="";
    else
        
$limit="limit ".intval($_REQUEST["list"]);
}

?>
<div id="menu">

<h1>Recent Posts</h1>
<ul>
<?php

$db
->query("select pid,poster,unix_timestamp()-unix_timestamp(posted) as age, ".
    
"date_format(posted, '%a %D %b %H:%i') as postdate ".
    
"from pastebin order by posted desc, pid desc $limit");
while (
$db->next_record())
{
    
$age=$db->f("age");
    
$days=floor($age/(3600*24));
    
$hours=floor($age/3600);
    
$minutes=floor($age/60);
    
$seconds=$age;
    
    if (
$days>1)
        
$age="$days days ago";
    elseif (
$hours>0)
        
$age="$hours hr".(($hours>1)?"s":"")." ago";
    elseif (
$minutes>0)
        
$age="$minutes min".(($minutes>1)?"s":"")." ago";
    else
        
$age="$seconds sec".(($seconds>1)?"s":"")." ago";
    
    if (
$_REQUEST["show"]==$db->f("pid"))
        
$cls=" class=\"highlight\"";
    else
        
$cls="";
            
    echo
"<li{$cls}><a href=\"".shorturl($db->f("pid"))."\">";
    echo
$db->f("poster");
    echo
"</a><br />\n";
    
    echo
$age;
    echo
"</li>\n\n";
}

echo
"<li><a href=\"pastebin.php\">Make new post</a></li>\n";
echo
"</ul>";
?>


<form method="get" action="http://www.php.net/search.php">
<h1>PHP Manual</h1>
<input type="text" size="9" name="pattern"/>
<input type="hidden" name="show" value="quickref"/>
<input type="submit" value="go"/>
</form>

<form method="get" action="http://www.mysql.com/search/?">
<h1>MySQL Manual</h1>
<input type="hidden" name="base" value="http://dev.mysql.com"/>
<input type="hidden" name="lang" value="en"/>
<input type="hidden" name="doc" value="1"/>
<input type="hidden" name="m" value="o"/>
<input type="text" size="9" name="q"/>
<input type="submit" value="go"/>
</form>

  
<p>
    <a href="http://validator.w3.org/check/referer"><img
        src="http://www.w3.org/Icons/valid-xhtml10"
        alt="Valid XHTML 1.0!" height="31" width="88" border="0"/></a>
</p>

</div>


<div id="content">

<?php

///////////////////////////////////////////////////////////////////////////////
// show processing errors
//
if (count($errors))
{
    echo
"<h1>Errors</h1><ul>";
    foreach(
$errors as $err)
    {
        echo
"<li>$err</li>";
    }
    echo
"</ul>";
    echo
"<hr />";
}

///////////////////////////////////////////////////////////////////////////////
// show a post
//
if (isset($_REQUEST["show"]))
{
    
    
$db->query("select *,date_format(posted, '%a %D %b %H:%i') as postdate ".
        
"from pastebin where pid='{$_REQUEST[show]}';");
    if (
$db->next_record())
    {
        
//show a quick reference url, poster and parents
        
echo "<h1>";
        
//echo shorturl($db->f("pid"))."<br />";
        
echo "Posted by ".$db->f("poster");
        echo
" ".$db->f("postdate");
                
        if (
$db->f("parent_pid")>0)
        {
            
$db2=new $dbclass;
            
$db2->query("select pid,poster, ".
                
"date_format(posted, '%a %D %b %H:%i') as posted ".
                
"from pastebin where pid=".$db->f("parent_pid"));
            if (
$db2->next_record())
            {
                echo
" (modification of posting from ";
                echo
"<a class=\"alt\" href=\"".shorturl($db2->f("pid"))."\">";
                echo
$db2->f("poster");
                echo
"</a> ";
                
                
//echo $db2->f("posted");
                
echo ")";
            }

        }
        
        echo
"</h1>";
        
        
//use configured highlighter...
        
$hclass="SyntaxHighlighter_".$syntax_highlighter;
        
$highlighter=new $hclass;
        
$code=$highlighter->highlight($db->f("code"));
    
        
        
//build a line numbering string
        
$lines="<code><font color=\"#999999\">";
        
        
$codeline=explode("<br />", $code);
        
$linecount = count($codeline);
        for(
$l=1; $l<=$linecount; $l++)
        {
            
$lines.=sprintf("%03d&nbsp;<br />", $l);
        }
        
$lines.="</font></code>";
        
        
//output
        
echo "<table><tr>";
        echo
"<td valign=\"top\">$lines</td><td valign=\"top\">$code</td>";
        echo
"</tr></table>";
        
        
//store the code for later editing
        
$editcode=$db->f("code");
        
        
//any amendments?
        
$count=0;
        
$db->query("select pid,poster,".
            
"date_format(posted, '%a %D %b %H:%i') as posted ".
            
"from pastebin where parent_pid=".$_REQUEST['show'].
            
" order by posted desc;");
        while (
$db->next_record())
        {
            if (
$count++ == 0)
                echo
"<br /><b>The following amendments have been posted:</b><ul>";
                
            echo
"<li>";
            
            echo
"<a href=\"".shorturl($db->f("pid"))."\">";
            echo
$db->f("poster");
            echo
"</a> (";

            echo
$db->f("posted");
            echo
")</li>";
        }

        if (
$count)
            echo
"</ul>";

        echo
"<br /><br /><b>Submit a correction or amendment below. (<a
href=\"pastebin.php\">click here to make a fresh posting</a>)</b>"
;
        
    }
    else
    {
        echo
"<b>Unknown post id, it may have been deleted</b><br />";
    }
}
else
{
    echo
"<h1>New posting</h1>";
}


///////////////////////////////////////////////////////////////////////////////
// submission form
//
$poster=$_COOKIE["persistName"];
if (
strlen($poster))
    
$remember="checked=\"checked\"";
else
    
$remember="";


?>
<form name="editor" method="post" action="<?php echo $GLOBALS["this_script"] ?>">
<input type="hidden" name="parent_pid" value="<?php echo $_REQUEST["show"] ?>"/>
<b>Name</b><br />
<input type="text" maxlength="24" size="24" name="poster" value="<?php echo $poster ?>" />
<input type="submit" name="paste" value="Send"/>
<br />
<input type="checkbox" name="remember" value="1" <?php echo $remember ?>/>Remember my name in a cookie
<br /><br />

<b>Code:</b> To ensure legibility, keep your code lines under 80 characters long.<br />
Include comments to indicate what you need feedback on.<br />


<script type="text/javascript" src="pastebin.js"></script>

<textarea id="code" class="codeedit" name="code2" cols="80" rows="10" onkeydown="checkTab(this)">
<?php echo htmlentities($editcode) ?>
</textarea>

</form>
  
</div>

</body>
</html>