// smd_remote_file by Stef Dawson
// Yuk :-(
global $smd_remote_file_vars;
$smd_remote_file_vars = array(
'msg' => '',
'min_txp_ver' => '4.0.6',
);
if (txpinterface === 'admin' && gps('event') === "file") {
if (version_compare(txp_version, $smd_remote_file_vars['min_txp_ver'], ">=")) {
register_callback('smd_remote_file_replace', 'file', 'smd_remote_file_replace');
register_callback('smd_remote_file_update', 'file', 'file_save');
register_callback('smd_remote_file_create', 'file', 'smd_remote_file_create', 1);
register_callback('smd_remote_file', 'file');
} else {
trigger_error(gTxt('txp_version') . " " .$smd_remote_file_vars['min_txp_ver']. " required.");
}
}
if (txpinterface === 'public') {
register_callback('smd_remote_download', 'file_download');
}
// Blow-by-blow equivalent of file_download_link, just a remote-aware version.
// Adds the choose option. Defaults to 0 ( = random, for load balancing). Specify
// any higher integer to grab that particular entry from the file (if it exists, else use 1st)
function smd_file_download_link($atts, $thing) {
global $thisfile;
extract(lAtts(array(
'filename' => '',
'id' => '',
'choose' => '0',
'show_link' => '0',
), $atts));
// Remove the extra attributes not in the orginal tag
unset($atts['show_link']);
unset($atts['choose']);
$keys = array("smd_choose" => $choose);
$out = file_download_link($atts, $thing);
if (strpos($thisfile['filename'], ".link")) {
$origLink = explode('"', $out);
$origLink[1] = (($show_link) ? $origLink[1] : str_replace(".link", "", $origLink[1])) . join_qs($keys); // Will ignore join_qs if choose is 0
$out = implode('"', $origLink);
}
return $out;
}
// Add an image to the download form which, by default, is based on the filename of the download itself
function smd_file_download_image($atts) {
global $thisfile;
assert_file();
extract(lAtts(array(
'filename' => '',
'id' => '',
'extension' => 'jpg',
'ifmissing' => '?ref',
'thumb' => '0',
'class' => '',
'wraptag' => '',
), $atts));
$filelink = $thisfile['filename'];
if ($filename == "") {
$filename = $filelink;
}
$filename = str_replace(".link", "", $filename) . (($extension=="") ? '' : '.'.$extension);
$img = '';
if ($id) {
$img = ($thumb==0) ? @image(array("id" => $id, "class" => $class, "wraptag" => $wraptag)) : @thumbnail(array("id" => $id, "class" => $class, "wraptag" => $wraptag));
} else if ((strpos($filename, "http://") === 0) || (strpos($filename, "/") === 0)) {
$img = (($wraptag=="") ? '' : '<'.$wraptag. (($class=="") ? '' : ' class="'.$class.'"') .'>') . ''. (($wraptag=="") ? '' : ''.$wraptag.'>');
} else {
$img = ($thumb==0) ? @image(array("name" => $filename, "class" => $class, "wraptag" => $wraptag)) : @thumbnail(array("name" => $filename, "class" => $class, "wraptag" => $wraptag));
}
$wrapper = (($wraptag=="") ? '@@REPL' : '<'.$wraptag. (($class=="") ? '' : ' class="'.$class.'"') .'>@@REPL'.$wraptag.'>');
if (strpos($ifmissing, "?ref") === 0) {
$display = ($id) ? $id : $filename;
$missing = str_replace("@@REPL", $display, $wrapper);
} else if (strpos($ifmissing, "?image") === 0) {
$imgParts = explode(":", $ifmissing);
if (count($imgParts) == 2) {
$imgOpts = array();
if(is_numeric($imgParts[1])) {
$imgOpts["id"] = $imgParts[1];
} else {
$imgOpts["name"] = $imgParts[1];
}
$missing = str_replace("@@REPL", (($thumb==0) ? @image($imgOpts) : @thumbnail($imgOpts)), $wrapper);
} else {
$missing = "";
}
} else if ($ifmissing == "") {
$missing = "";
} else {
$missing = str_replace("@@REPL", $ifmissing, $wrapper);
}
return ($img) ? $img : $missing;
}
// Generic callback which is fired _after_ the Files page has loaded.
// Performs display cleanup/insertion and post processing of any file inserts/edits
function smd_remote_file($event, $step) {
global $smd_remote_file_vars;
$helpLink = '?';
if ($step == "file_edit" || $step == "file_replace") {
$id = assert_int(gps('id'));
$rs = safe_row('filename','txp_file','id = '. $id);
if (strpos($rs['filename'], ".link") !== false) {
$ul_form = trim(form(eInput('file'). sInput('smd_remote_file_replace'). hInput('id',$id).
graf('Add URL'.sp.$helpLink.sp.fInput('text', 'smd_remote_url', '', 'edit', 'Enter a URL to add to this file', '', '32').sp.
"Overwrite:".sp.checkbox('smd_remote_blat', 'smd_remote_blat', 0).sp.
fInput('submit', '', 'Upload', 'smallerbox'))
, 'text-align: center;'));
echo smd_remote_js('$(".upload-form").replaceWith(\''.$ul_form.'\');');
}
} else {
$ul_form = trim(form(eInput('file'). sInput('smd_remote_file_create').
graf('or URL'.sp.$helpLink.sp.fInput('text', 'smd_remote_url', '', 'edit', 'Enter a URL to upload to TXP', '', '32').sp.
fInput('submit', '', 'Upload', 'smallerbox'))
, 'text-align: center;'));
echo smd_remote_js('$(".upload-form").append(\''.$ul_form.'\');');
}
if ($smd_remote_file_vars['msg'] != "") {
echo smd_remote_js('$("#nav-primary table td:eq(0)").append(\''.$smd_remote_file_vars['msg'].'\');');
}
}
// When a file is "replaced" with a new URL the existing file name must remain
// unchanged. By default the new URL is appended to the .link file unless the 'overwrite'
// checkbox is set
function smd_remote_file_replace() {
global $file_base_path, $smd_remote_file_vars;
extract(gpsa(array('smd_remote_url', 'smd_remote_blat', 'id')));
$id = assert_int($id);
$url = trim($smd_remote_url);
$rs = safe_row('filename','txp_file','id = '.$id);
if (strpos($rs['filename'], ".link") !== false) {
if (strpos($url, "http") === 0) {
$writeMode = ($smd_remote_blat) ? "w" : "a";
$dest_filepath = build_file_path($file_base_path, $rs['filename']);
smd_remote_file_write($dest_filepath, $rs['filename'], $url, $writeMode);
} else {
$smd_remote_file_vars['msg'] = gTxt('file_upload_failed') . ((empty($smd_remote_url)) ? ' - '.gTxt('upload_err_no_file') : '');
}
}
}
// Every time a file is saved/edited, TXP recalculates its size from the real file (grrr).
// This is undesirable so it is replaced with the size of the remote URL file instead.
function smd_remote_file_update() {
extract(gpsa(array('id')));
smd_remote_set_size($id);
}
// Sets the size of the given TXP database file to that of its corresponding "real" remote URL file size
function smd_remote_set_size($id_or_file) {
global $file_base_path;
if (is_numeric($id_or_file)) {
$filename = trim(safe_field("filename", "txp_file", "id=".intval($id_or_file)));
} else {
$filename = trim(doSlash($id_or_file));
}
if (strpos($filename, ".link")) {
$filepath = build_file_path($file_base_path, $filename);
$url = smd_remote_file_list($filepath, 1, 1);
if (count($url) > 0) {
$hdrs = smd_get_headers($url[0], 1);
$size = ($hdrs === false || !isset($hdrs['content-length'])) ? 1 : $hdrs['content-length'];
safe_update("txp_file", "size=".$size, "filename='".$filename."'");
}
}
}
// Callback for uploading a URL from the Files tab
function smd_remote_file_create() {
global $file_base_path, $smd_remote_file_vars;
extract(doSlash(gpsa(array('smd_remote_url','category','permissions','description'))));
$url = trim($smd_remote_url);
// Only intercept remote files; leave everything else for TXP to manage
if (strpos($url, "http") === 0) {
$hdrs = smd_get_headers($url, 1);
$size = ($hdrs === false || !isset($hdrs['content-length'])) ? 1 : $hdrs['content-length'];
// Make a filename and full path: unencoded
$dest_filename = basename(urldecode($url)).".link";
$dest_filepath = build_file_path($file_base_path, $dest_filename);
if (file_exists($dest_filepath)) {
smd_remote_file_write($dest_filepath, $dest_filename, $url);
} else {
// File doesn't exist so create it and put the URL inside
$tmp = tempnam("/tmp", "smd_");
$handle = fopen($tmp, "w");
fwrite($handle, $url.n);
fclose($handle);
rename($tmp, $dest_filepath);
// Add the file to TXP
$ret = safe_insert("txp_file",
"filename = '$dest_filename',
category = '$category',
permissions = '$permissions',
description = '$description',
size = '$size',
created = now(),
modified = now()
");
$smd_remote_file_vars['msg'] = gTxt('file_uploaded', array('{name}' => urldecode($url)));
}
} else {
$smd_remote_file_vars['msg'] = gTxt('file_upload_failed') . ((empty($smd_remote_url)) ? ' - '.gTxt('upload_err_no_file') : '');
}
}
// Append a URL to the given file. If writeMode="w" the whole file is replaced
function smd_remote_file_write($filepath, $filename, $url, $writeMode="a") {
global $smd_remote_file_vars;
// Read the whole file because we only want to add the URL if it's not there already
$lines = smd_remote_file_list($filepath, 0, 1);
if (!in_array($url, $lines) || $writeMode == "w") {
$handle = fopen($filepath, $writeMode);
fwrite($handle, $url.n);
fclose($handle);
$smd_remote_file_vars['msg'] = gTxt('file_uploaded', array('{name}' => urldecode($url)));
} else {
$smd_remote_file_vars['msg'] = gTxt('file_already-exists', array('{name}' => urldecode($url)));
}
// Set the size just in case
smd_remote_set_size($filename);
}
// Read the contents of the chosen file (full path required) and get lines from within, adding them to an array.
// $offset is where to start from. Normally 1 = 1st row, 2 = 2nd row and so on. 0 = a random row.
// $qty specifies how many rows to pull. 0 = unlimited.
function smd_remote_file_list($fname, $qty=1, $offset=0) {
$out = array();
if (file_exists($fname)) {
$fd = fopen($fname, "r");
// Read the whole file in (yes there's the file() call, but fgets() is supposedly quicker on txt files)
while (!feof($fd)) {
$line = rtrim(fgets($fd));
if ($line != "") {
$lines[] = $line;
}
}
fclose ($fd);
if ($offset == 0) {
shuffle($lines);
$offset = 1;
}
$offset = ($offset > count($lines)) ? 1 : $offset;
$out = ($qty == 0) ? $lines : array_slice($lines, $offset-1, $qty);
}
return $out;
}
// Called just before a download is initiated
function smd_remote_download($event, $step) {
global $pretext, $id, $file_base_path, $file_error;
if (!isset($file_error)) {
// Get the "true" filename (unfortunately from the database = 1 extra query).
$real_file = safe_row("filename, size", "txp_file", "id=".intval($id));
if (strpos($real_file['filename'], ".link") > 0) {
$choose = 0;
// Get any overriding value of smd_choose from the query string
if ($pretext['qs']) {
list($qkey, $qval) = explode("=", $pretext['qs']);
if ($qkey == "smd_choose") {
if ($qval > 0) {
$choose = intval($qval);
}
}
}
// The file size, however, is that of the remote file
$remoteURL = smd_remote_file_list(build_file_path($file_base_path, $real_file['filename']), 1, $choose);
if (count($remoteURL) > 0) {
$url = $remoteURL[0];
// Test the file exists: slow, but reduces false download count increments
$hdrs = smd_get_headers($url, 1);
$allkey = strtolower(implode(" ", array_keys($hdrs)));
if (strpos($allkey, "200") > 0 && strpos($allkey, "ok") > 0) {
header('Content-Description: File Download');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename="' . basename($real_file['filename']) . '"; size = "'.$real_file['size'].'"');
// Fix for lame IE 6 pdf bug on servers configured to send cache headers
header('Cache-Control: private');
@ini_set("zlib.output_compression", "Off");
@set_time_limit(0);
@ignore_user_abort(true);
// Hand-off to the remote file
header('Location: ' . $url);
// record download if the file sizes match
if (intval($hdrs['content-length']) == intval($real_file['size'])) {
safe_update("txp_file", "downloads=downloads+1", 'id='.intval($id));
log_hit('200');
}
// remote download done: game over
exit(0);
} else {
$file_error = 404;
}
} else {
$file_error = 404;
}
}
}
// remote download not done - leave to TXP to handle error or "local" file download
return;
}
function smd_remote_js($content) {
$out = ''.n;
return $out;
}
// PHP4 emulation(ish) of PHP5's get_headers(). Stolen from php.net and modded
function smd_get_headers($url, $format=0) {
if (!$url) {
return false;
}
$uinfo=parse_url($url);
$headers = array();
if (is_callable('checkdnsrr') && !checkdnsrr($uinfo['host'].'.','MX') && !checkdnsrr($uinfo['host'].'.','A')) {
return false;
}
$port = isset($uinfo['port']) ? $uinfo['port'] : 80;
$fp=fsockopen($uinfo['host'], $port, $errno, $errstr, 5);
if($fp) {
$head = "GET ".@$uinfo['path']."?".@$uinfo['query']." HTTP/1.0\r\n";
$head .= "Host: ".@$uinfo['host'].":".$port."\r\n";
$head .= "Connection: Close\r\n";
$head .= "Accept: */*\r\n";
if (@$uinfo['user']) {
$head .= "Authorization: Basic ".base64_encode($uinfo['user'].':'.$uinfo['pass'])."\r\n";
}
$head .= "\r\n";
fputs($fp, $head);
$eoheader = false;
while(!feof($fp) or ($eoheader==true)) {
if($header=fgets($fp, 1024)) {
if ($header == "\r\n") {
$eoheader = true;
break;
} else {
$header = trim($header);
}
if($format == 1) {
$key = strtolower(array_shift(explode(': ',$header)));
if($key == $header) {
$headers[] = $header;
} else {
$headers[$key]=substr($header,strlen($key)+2);
}
unset($key);
} else {
$headers[] = $header;
}
}
}
return $headers;
} else {
return false;
}
}