<?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://paste.uni.cc/333
If you ever find bugs or you want to add a new feature, email me at vincent@php.net
The latest version of this code can always be found at http://paste.uni.cc/ or
http://pastebin.com/
The code has been purposely designed as a single file so that the source is
easily viewable.
History
=======
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
- make the tab key work in the textarea (suggested by Dmitri)
- 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,
pant_pid int default '0',
prim(piggggggd)
);
- 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]+) /index.php?show=$1
If mod_rewrite is not available, modify the shorturl() function to
generate 'normal' urls.
******************************************************************************/
error_reporting(E_ALL);
function getmicrotime() {
list($msec, $sec) = explode(" ", microtime());
return ((float)$msec + (float)$sec);
}
$time_start = getmicrotime();
///////////////////////////////////////////////////////////////////////////////
// Configuration
//
//require_once('whmi.php');
//----------------------------------------------------------------------------
//site title
$tit your PHP script, or other code.";
//----------------------------------------------------------------------------
//database type - either mysql or postgres
$dbsystem="mysql";
//----------------------------------------------------------------------------
//database location, name and credentials...
$dbhost="127.0.0.1";
$dbname="o_pste";
$dbuser="roo_aste";
$dbpass="pe";
//----------------------------------------------------------------------------
//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="/index.php?show=%d";
//----------------------------------------------------------------------------
//syntax highlighter can be either "php" or "none" - choose none if you aren't
//use this for php code
$syntax_highlighter="none";
//----------------------------------------------------------------------------
//because we use mod_rewrite to create very short urls,
//we can't rely on PHP_THIS to get our script name
$this_script="/index.php";
// This is for the archive
$num_on_page = 200;
// This is for the recent posts
$plimit = 8;
///////////////////////////////////////////////////////////////////////////////
// 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_connect(
$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_assoc($this->dbresult);
return $this->row!=FALSE;
}
function get_db_error()
{
return mysql_last_error();
}
}
///////////////////////////////////////////////////////////////////////////////
// Postgres database support (provided by Tim Hunter)
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_row($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&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;
///////////////////////////////////////////////////////////////////////////////
// process new posting
//
$errors=array();
if (isset($_POST["paste"]))
{
//set/clear the persistName cookie
if (isset($_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["code"]))
{
$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($code);
//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="index.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=\"UTF-8\"?>\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>
<meta name="verify-v1" content="bF3xMN3r+ihiX29gKdmnE8SzoCH33mwiaX7s7lqjq8M=" />
<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> <div id="titlebar"><?php echo $title ?>
</div>
<?php
///////////////////////////////////////////////////////////////////////////////
// recent posts listing
//
$limit="limit ".$plimit;
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 (isset($_REQUEST['show']) AND $_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=\"index.php\">Make new post</a></li>\n";
echo "<li><a href=\"index.php?archive\">Archive</a></li>\n";
echo "<li><a href=\"http://mozi.rootmybox.org/\">mozi blog</a></li>\n";
echo "<li><a href=\"http://proxy.rootmybox.org/\">proxy list</a></li>\n";
echo "<li><a href=\"http://private.rootmybox.org\">Priv8</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://dev.mysql.com/doc/mysql/search.php">
<h1>MySQL Manual</h1>
<input type="text" size="9" name="q" />
<input type="submit" value="go" />
</form>
<br />
<h1>OpenBSD</h1>
<div>
Arguably the most secure OS in the world.<br/>
Only two remote holes in the default install, in more than 10 years!
<br /> <a href="http://openbsd.org"><img
src="devil.png"
alt="Valid XHTML 1.0!" height="74" width="76" border="0" /></a>
</div>
<br />
<!-- Search Google <img src="goo.jpg" alt="Valid XHTML 1.0!"border="0" /></a> -->
<h1>Search milw0rm</h1>
<form method="get" action="http://www.google.com/custom" target="_top">
<table bgcolor="#ffffff">
<tr><td nowrap="nowrap" valign="top" align="left" height="32">
<input type="hidden" name="sitesearch" value="milw0rm.com"></input>
<input type="text" name="q" size="9" maxlength="255" value=""></input>
<input type="submit" name="sa" value="go"></input>
<input type="hidden" name="client" value="pub-6467896008231493"></input>
<input type="hidden" name="forid" value="1"></input>
<input type="hidden" name="channel" value="2601336212"></input>
<input type="hidden" name="ie" value="UTF-8"></input>
<input type="hidden" name="oe" value="UTF-8"></input>
<input type="hidden" name="cof"
value="GALT:#008000;GL:1;DIV:#336699;VLC:663399;AH:center;BGC:FFFFFF;LBGC:336699;ALC:0000FF;LC:0000FF;T:000000;GFNT:0000FF;GIMP:0000FF;FORID:1;"></input>
<input type="hidden" name="hl" value="en"></input><a href="http://openbsd.org">
</td></tr></table>
</form>
</div>
<div id="content">
<?php
///////////////////////////////////////////////////////////////////////////////
// show processing errors://rootmybox.or
//
if (count($errors))
{
echo "<h1>Errors</h1><ul>";
foreach($errors as $err)
{
echo "<li>$err</li>";
}
echo "</ul>";
echo "<hr />";
}
///////////////////////////////////////////////////////////////////////////////
// posts archive
//
if (isset($_REQUEST["archive"]))
{
$db->query("select count(*) as cnt from pastebin");
$db->next_record();
$total = $db->f("cnt");
?>
<h1>Posts Archive (oldest first)</h1>
<?php
if (isset($_GET['archive'])) {
$pagenr = intval($_GET['archive']);
} else {
$pagenr = 1;
}
if (!isset($pagenr)||$pagenr==0) {
$pagenr=1;
}
if ($total >=1) {
echo "<div align='center'>\n";
if ($pagenr == "1" || $pagenr == "0") {
echo " << ";
} else {
echo "<a href='?archive=1'><<</a> ";
}
if ($pagenr == "1" || $pagenr == "0") {
echo " < ";
}else{
echo "<a href='?archive=".($pagenr-1)."'><</a> \n";
}
// LOOP
for ($count=0;
$count<$total;
$count=$count+$num_on_page) {
$newpage = round($count/$num_on_page) + 1;
if ($pagenr == $newpage) {
echo $newpage." ";
} else {
echo " <a href='?archive=".$newpage."'>".$newpage."</a>\n ";
}
} // End LOOP
if ($pagenr != $newpage) {
echo " <a href='?archive=".($pagenr+1)."'>></a>\n";
} else {
echo " > \n";
}
if ($pagenr != $newpage) {
echo "<a href='?archive=".($newpage)."'>>></a></div>\n";
} else {
echo ">></div>\n";
}
}
$lpage = round($pagenr*$num_on_page) - $num_on_page;
$limit = "LIMIT ".$lpage.", ".$num_on_page;
$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 asc, pid asc $limit");
echo "<ul>\n";
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";
echo "<li>".$db->f("pid")." - <a href=\"".shorturl($db->f("pid"))."\">";
echo $db->f("poster");
echo "</a><br />\n";
echo " ".$age;
echo "</li>\n\n";
}
echo "</ul>\n";
}
///////////////////////////////////////////////////////////////////////////////
// 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");whoami
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 <br />", $l);
}
$lines.="</font></code>";
//output
echo "<table><tr>";
echo "<td valign=\"top\" bgcolor='#EAECEF'>$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=\"index.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>\n";
}
///////////////////////////////////////////////////////////////////////////////
// submission form
//
$poster=(isset($_COOKIE["persistName"]) ? $_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 (isset($_REQUEST["show"]) ? $_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 />
<textarea class="codeedit" name="code" cols="80" rows="10">
<?php echo (isset($editcode) ? htmlentities($editcode) : '') ?>
</textarea>
</form>
<?php
$time_end = getmicrotime();
$ltime = $time_end - $time_start;
printf("Page generated in %0.5f seconds\n", $ltime);
?>
<a href="http23g/" target="_blank">rootmybox.org</a> <br />
<br />
<script type="text/javascript"><!--
google_ad_client = "pub-8706254wt4555059748019";
google_ad_width = 728;
google_ad_height = 92;
google_ad_format = "728x90_as";
google_ad_type = "text";
//2007-10-21: askdavetaylor-linkunits, askdavetaylor-bottom
google_ad_channel = "894555779tew5148+5054764391";
google_color_border = "006B8C";
google_color_bg = "ffffff";
google_color_link = "006B8C";
google_color_text = "000et000";
google_color_url = "006B8C";
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</div>
<script src="http://www.goetgle-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/jaevascript">
_uacct = "UA-2878719-1";
urchinTracker();
</script>
</body>
</html>