ocPortal Developer's Guide: Attachments
» Return to Contents
sources/attachments.php
Global_functions_attachments.php
Function summary
|
void
|
attachments_script ()
|
|
boolean
|
has_attachment_access (MEMBER member, AUTO_LINK id, ?object connection)
|
|
void
|
attachment_popup_script ()
|
|
tempcode
|
render_attachment (ID_TEXT tag, array attributes, array attachment, string pass_id, MEMBER source_member, boolean as_admin, object connection, ?array highlight_bits, ?MEMBER on_behalf_of_member, boolean semiparse_mode)
|
void attachments_script()
Show the image of an attachment/thumbnail.
Parameters…
(No return value)
function attachments_script()
{
// Closed site
$site_closed=get_option('site_closed');
if (($site_closed=='1') && (!has_specific_permission(get_member(),'access_closed_site')) && (!$GLOBALS['IS_ACTUALLY_ADMIN']))
{
header('Content-Type: text/plain');
@exit(get_option('closed'));
}
$id=get_param_integer('id',0);
$connection=$GLOBALS[(get_param_integer('forum_db',0)==1)?'FORUM_DB':'SITE_DB'];
$has_no_restricts=!is_null($connection->query_value_null_ok('attachment_refs','id',array('r_referer_type'=>'null','a_id'=>$id)));
if (!$has_no_restricts)
{
global $SITE_INFO;
if ((!is_guest()) || (!isset($SITE_INFO['any_guest_cached_too'])) || ($SITE_INFO['any_guest_cached_too']=='0'))
{
if ((get_param('for_session','-1')!=md5(strval(get_session_id()))) && (get_option('anti_leech')=='1') && (ocp_srv('HTTP_REFERER')!=''))
warn_exit(do_lang_tempcode('LEECH_BLOCK'));
}
}
require_lang('comcode');
// Lookup
$rows=$connection->query_select('attachments',array('*'),array('id'=>$id),'ORDER BY a_add_time DESC');
if (!array_key_exists(0,$rows)) warn_exit(do_lang_tempcode('MISSING_RESOURCE'));
$myrow=$rows[0];
header('Last-Modified: '.gmdate('D, d M Y H:i:s \G\M\T',$myrow['a_add_time']));
if ($myrow['a_url']=='') warn_exit(do_lang_tempcode('INTERNAL_ERROR'));
if (!$has_no_restricts)
{
// Permission
if (substr($myrow['a_url'],0,20)=='uploads/attachments/')
{
if (!has_attachment_access(get_member(),$id,$connection))
access_denied('ATTACHMENT_ACCESS');
}
}
$thumb=get_param_integer('thumb',0);
if ($thumb==1)
{
$full=$myrow['a_thumb_url'];
require_code('images');
$myrow['a_thumb_url']=ensure_thumbnail($myrow['a_url'],$myrow['a_thumb_url'],'attachments','attachments',intval($myrow['id']),'a_thumb_url');
}
else
{
$full=$myrow['a_url'];
if (get_param_integer('no_count',0)==0)
{
// Update download count
if (ocp_srv('HTTP_RANGE')=='')
$connection->query_update('attachments',array('a_num_downloads'=>$myrow['a_num_downloads']+1,'a_last_downloaded_time'=>time()),array('id'=>$id),'',1);
}
}
// Is it non-local? If so, redirect
if (!url_is_local($full))
{
if ((strpos($full,chr(10))!==false) || (strpos($full,chr(13))!==false))
log_hack_attack_and_exit('HEADER_SPLIT_HACK');
header('Location: '.$full);
return;
}
// $breakdown=pathinfo($full);
// $filename=$breakdown['basename'];
$_full=get_custom_file_base().'/'.rawurldecode($full);
if (!file_exists($_full)) warn_exit(do_lang_tempcode('_MISSING_RESOURCE','url:'.escape_html($full))); // File is missing, we can't do anything
$size=filesize($_full);
$original_filename=$myrow['a_original_filename'];
$extension=get_file_extension($original_filename);
require_code('files2');
check_shared_bandwidth_usage($size);
require_code('mime_types');
$mime_type=get_mime_type($extension);
/*$myfile2=fopen('test','wb');
fwrite($myfile2,var_export($_SERVER,true));
fwrite($myfile2,var_export($_ENV,true));
fclose($myfile2);*/
// Send header
if ((strpos($original_filename,chr(10))!==false) || (strpos($original_filename,chr(13))!==false))
log_hack_attack_and_exit('HEADER_SPLIT_HACK');
header('Content-Type: '.$mime_type.'; authoritative=true;');
//if ($mime_type=='application/octet-stream') Not sure about this at time of writing
{
if (strstr(ocp_srv('HTTP_USER_AGENT'),'MSIE')!==false)
{
header('Content-Disposition: filename="'.$original_filename.'"');
}/* elseif (substr($original_filename,-4)=='.pdf')
{
header('Content-Disposition: attachment; filename="'.$original_filename.'"');
} */else
{
header('Content-Disposition: inline; filename="'.$original_filename.'"');
}
}
header('Accept-Ranges: bytes');
// Caching
header("Pragma: private");
header("Cache-Control: private");
header('Expires: '.gmdate('D, d M Y H:i:s',time()+60*60*24*365).' GMT');
header('Last-Modified: '.gmdate('D, d M Y H:i:s',$myrow['a_add_time']).' GMT');
// Default to no resume
$from=0;
$new_length=$size;
@ini_set('zlib.output_compression','Off');
// They're trying to resume (so update our range)
$httprange=ocp_srv('HTTP_RANGE');
if (strlen($httprange)>0)
{
$_range=explode('=',ocp_srv('HTTP_RANGE'));
if (count($_range)==2)
{
if (strpos($_range[0],'-')===false) $_range=array_reverse($_range);
$range=$_range[0];
if (substr($range,0,1)=='-') $range=strval($size-intval(substr($range,1))-1).$range;
if (substr($range,-1,1)=='-') $range.=strval($size-1);
$bits=explode('-',$range);
if (count($bits)==2)
{
list($from,$to)=array_map('intval',$bits);
if (($to-$from!=0) || ($from==0)) // Workaround to weird behaviour on Chrome
{
$new_length=$to-$from+1;
header('HTTP/1.1 206 Partial Content');
header('Content-Range: bytes '.$range.'/'.strval($size));
} else
{
$from=0;
}
}
}
}
header('Content-Length: '.strval($new_length));
if (function_exists('set_time_limit')) @set_time_limit(0);
error_reporting(0);
if ($from==0)
$GLOBALS['SITE_DB']->query('UPDATE '.get_table_prefix().'values SET the_value=(the_value+'.strval((integer)$size).') WHERE the_name=\'download_bandwidth\'',1);
@ini_set('ocproducts.xss_detect','0');
// Send actual data
$myfile=fopen($_full,'rb');
fseek($myfile,$from);
/*if ($size==$new_length) Uses a lot of memory :S
{
fpassthru($myfile);
} else*/
{
$i=0;
flush(); // Works around weird PHP bug that sends data before headers, on some PHP versions
while ($i<$new_length)
{
$content=fread($myfile,min($new_length-$i,1048576));
echo $content;
$len=strlen($content);
if ($len==0) break;
$i+=$len;
}
fclose($myfile);
}
}
boolean has_attachment_access(MEMBER member, AUTO_LINK id, ?object connection)
Find if the specified member has access to view the specified attachment.
Parameters…
| Name |
member |
| Description |
The member being checked whether to have the access |
| Type |
MEMBER |
| Name |
id |
| Description |
The ID code for the attachment being checked |
| Type |
AUTO_LINK |
| Name |
connection |
| Description |
The database connection to use (NULL: site DB) |
| Default value |
|
| Type |
?object |
Returns…
| Description |
Whether the member has attachment access |
| Type |
boolean |
function has_attachment_access($member,$id,$connection=NULL)
{
if (is_null($connection)) $connection=$GLOBALS['SITE_DB'];
if ($GLOBALS['FORUM_DRIVER']->is_super_admin($member)) return true;
$refs=$connection->query_select('attachment_refs',array('r_referer_type','r_referer_id'),array('a_id'=>$id));
foreach ($refs as $ref)
{
$type=$ref['r_referer_type'];
$ref_id=$ref['r_referer_id'];
if ((file_exists(get_file_base().'/sources/hooks/systems/attachments/'.filter_naughty_harsh($type).'.php')) || (file_exists(get_file_base().'/sources_custom/hooks/systems/attachments/'.filter_naughty_harsh($type).'.php')))
{
require_code('hooks/systems/attachments/'.filter_naughty_harsh($type));
$object=object_factory('Hook_attachments_'.filter_naughty_harsh($type));
if ($object->run($ref_id,$connection)) return true;
}
}
return false;
}
void attachment_popup_script()
Shows an HTML page of all attachments we can access with selection buttons.
Parameters…
(No return value)
tempcode render_attachment(ID_TEXT tag, array attributes, array attachment, string pass_id, MEMBER source_member, boolean as_admin, object connection, ?array highlight_bits, ?MEMBER on_behalf_of_member, boolean semiparse_mode)
Get tempcode for a Comcode rich-media attachment.
Parameters…
| Name |
tag |
| Description |
The attachment tag |
| Type |
ID_TEXT |
| Values restricted to |
attachment attachment_safe attachment2 |
| Name |
attributes |
| Description |
A map of the attributes (name=>val) for the tag |
| Type |
array |
| Name |
attachment |
| Description |
A map of the attachment properties (name=>val) for the attachment |
| Type |
array |
| Name |
pass_id |
| Description |
A special identifier to mark where the resultant tempcode is going to end up (e.g. the ID of a post) |
| Type |
string |
| Name |
source_member |
| Description |
The member who is responsible for this Comcode |
| Type |
MEMBER |
| Name |
as_admin |
| Description |
Whether to check as arbitrary admin |
| Type |
boolean |
| Name |
connection |
| Description |
The database connection to use |
| Type |
object |
| Name |
highlight_bits |
| Description |
A list of words to highlight (NULL: none) |
| Default value |
|
| Type |
?array |
| Name |
on_behalf_of_member |
| Description |
The member we are running on behalf of, with respect to how attachments are handled; we may use this members attachments that are already within this post, and our new attachments will be handed to this member (NULL: member evaluating) |
| Default value |
|
| Type |
?MEMBER |
| Name |
semiparse_mode |
| Description |
Whether to parse so as to create something that would fit inside a semihtml tag. It means we generate HTML, with Comcode written into it where the tag could never be reverse-converted (e.g. a block). |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The tempcode for the attachment |
| Type |
tempcode |
function render_attachment($tag,$attributes,$attachment,$pass_id,$source_member,$as_admin,$connection,$highlight_bits=NULL,$on_behalf_of_member=NULL,$semiparse_mode=false)
{
require_code('comcode_renderer');
$extension=get_file_extension($attachment['a_original_filename']);
require_code('mime_types');
$mime_type=get_mime_type($extension);
$attachment['CLEAN_SIZE']=clean_file_size($attachment['a_file_size']);
$attachment['MIME_TYPE']=$mime_type;
$attachment['PASS_ID']=(intval($pass_id)<0)?strval(mt_rand(0,10000)):$pass_id;
$attachment['SCRIPT']=find_script('attachment');
$attachment['RAND']=strval(mt_rand(0,32000));
if ($connection->connection_write!=$GLOBALS['SITE_DB']->connection_write)
{
$attachment['SUP_PARAMS']='&forum_db=1';
$attachment['FORUM_DB_BIN']='1';
} else
{
$attachment['SUP_PARAMS']='';
$attachment['FORUM_DB_BIN']='';
}
$type=trim(array_key_exists('type',$attributes)?$attributes['type']:'auto');
$attachment['id']=strval($attachment['id']);
$attachment['a_member_id']=strval($attachment['a_member_id']);
$attachment['a_file_size']=strval($attachment['a_file_size']);
$attachment['a_last_downloaded_time']=is_null($attachment['a_last_downloaded_time'])?'':strval($attachment['a_last_downloaded_time']);
$attachment['a_add_time']=strval($attachment['a_add_time']);
$attachment['a_num_downloads']=integer_format($attachment['a_num_downloads']);
require_code('images');
$attachment['a_width']=array_key_exists('width',$attributes)?strval(intval($attributes['width'])):'';
$attachment['a_height']=array_key_exists('height',$attributes)?strval(intval($attributes['height'])):'';
if (($attachment['a_width']=='') || ($attachment['a_height']==''))
{
if ((addon_installed('galleries')) && (is_video($attachment['a_original_filename'])) && (url_is_local($attachment['a_url'])))
{
require_code('galleries2');
$vid_details=get_video_details(get_custom_file_base().'/'.rawurldecode($attachment['a_url']),$attachment['a_original_filename'],true);
if ($vid_details!==false)
{
list($_width,$_height,)=$vid_details;
if ($attachment['a_width']=='') $attachment['a_width']=strval($_width);
if ($attachment['a_height']=='') $attachment['a_height']=strval($_height);
}
}
if (($attachment['a_width']=='') || ($attachment['a_height']==''))
{
if ($attachment['a_width']=='') $attachment['a_width']='240';
if ($attachment['a_height']=='') $attachment['a_height']='216';
}
}
$attachment['a_align']=array_key_exists('align',$attributes)?$attributes['align']:'left';
if (!array_key_exists('a_description',$attachment)) // All quite messy, because descriptions might source from attachments table (for existing attachments with no overridden Comcode description), from Comcode parameter (for attachments with description), or from POST environment (for new attachments)
{
if (array_key_exists('description',$attributes)) $attachment['description']=$attributes['description'];
if (!array_key_exists('description',$attachment)) $attachment['description']='';
$attachment['a_description']=is_object($attachment['description'])?$attachment['description']:comcode_to_tempcode($attachment['description'],$source_member,$as_admin,60,NULL,$connection,false,false,false,false,false,NULL,$on_behalf_of_member);
}
$attachment['a_type']=$type;
$attachment['a_thumb']=array_key_exists('thumb',$attributes)?$attributes['thumb']:'1';
if ($attachment['a_thumb']!='0') $attachment['a_thumb']='1';
switch ($type)
{
case 'email':
require_code('mail');
global $EMAIL_ATTACHMENTS;
if (url_is_local($attachment['a_url'])) $attachment['a_url']=get_custom_base_url().'/'.$attachment['a_url'];
$EMAIL_ATTACHMENTS[$attachment['a_url']]=$attachment['a_original_filename'];
$temp_tpl=new ocp_tempcode();
break;
case 'code':
$url=$attachment['a_url'];
if (url_is_local($url)) $url=get_custom_base_url().'/'.$url;
$file_contents=http_download_file($url,1024*1024*20/*reasonable limit*/);
list($_embed,$title)=do_code_box($extension,make_string_tempcode($file_contents));
if ($attachment['a_original_filename']!='') $title=escape_html($attachment['a_original_filename']);
$temp_tpl=do_template('COMCODE_CODE',array('WYSIWYG_SAFE'=>($tag=='attachment')?NULL:true,'STYLE'=>'','TYPE'=>$extension,'CONTENT'=>$_embed,'TITLE'=>$title));
break;
case 'hyperlink':
if ($tag=='attachment')
{
$keep=symbol_tempcode('KEEP');
$_url=new ocp_tempcode();
$_url->attach(find_script('attachment').'?id='.urlencode($attachment['id']).$keep->evaluate().'&for_session=');
$_url->attach(symbol_tempcode('SESSION_HASHED'));
}
$temp_tpl=hyperlink($_url,($attachment['a_description']!='')?$attachment['a_description']:$attachment['a_original_filename'],true);
break;
default:
if (is_image($attachment['a_original_filename']))
{
if (($type=='inline') || ($type=='left_inline') || ($type=='right_inline')) $attachment['mini']='1';
require_code('images');
ensure_thumbnail($attachment['a_url'],$attachment['a_thumb_url'],'attachments','attachments',intval($attachment['id']),'a_thumb_url');
$temp_tpl=do_template('ATTACHMENT_IMG'.(((array_key_exists('mini',$attachment)) && ($attachment['mini']=='1'))?'_MINI':''),map_keys_to_upper($attachment)+array('WYSIWYG_SAFE'=>($tag=='attachment')?NULL:true));
if (($type=='left') || ($type=='left_inline'))
{
$temp_tpl=do_template('ATTACHMENT_LEFT',array('_GUID'=>'aee2a6842d369c8dae212c3478a3a3e9','WYSIWYG_SAFE'=>($tag=='attachment')?NULL:true,'CONTENT'=>$temp_tpl));
}
if (($type=='right') || ($type=='right_inline'))
{
$temp_tpl=do_template('ATTACHMENT_RIGHT',array('_GUID'=>'1a7209d67d91db740c86e7a331720195','WYSIWYG_SAFE'=>($tag=='attachment')?NULL:true,'CONTENT'=>$temp_tpl));
}
break;
}
elseif ($extension=='swf')
{
$temp_tpl=do_template('ATTACHMENT_SWF',map_keys_to_upper($attachment)+array('WYSIWYG_SAFE'=>($tag=='attachment')?NULL:true));
break;
}
elseif ((addon_installed('jwplayer')) && (($mime_type=='video/x-flv') || ($mime_type=='video/mp4') || ($mime_type=='video/webm')))
{
$temp_tpl=do_template('ATTACHMENT_FLV',map_keys_to_upper($attachment)+array('WYSIWYG_SAFE'=>($tag=='attachment')?NULL:true));
break;
}
elseif ($mime_type=='video/quicktime')
{
$temp_tpl=do_template('ATTACHMENT_QT',map_keys_to_upper($attachment)+array('WYSIWYG_SAFE'=>($tag=='attachment')?NULL:true));
break;
}
elseif ($mime_type=='audio/x-pn-realaudio')
{
$temp_tpl=do_template('ATTACHMENT_RM',map_keys_to_upper($attachment)+array('WYSIWYG_SAFE'=>($tag=='attachment')?NULL:true));
break;
}
elseif ((substr($mime_type,0,5)=='video') || (substr($mime_type,0,5)=='audio'))
{
$temp_tpl=do_template('ATTACHMENT_MEDIA',map_keys_to_upper($attachment)+array('WYSIWYG_SAFE'=>($tag=='attachment')?NULL:true));
break;
}
// Continues on, as it's not a media type...
case 'download':
if (is_null($attachment['a_file_size']))
{
$temp_tpl=do_template('ATTACHMENT_DOWNLOAD_REMOTE',map_keys_to_upper($attachment)+array('WYSIWYG_SAFE'=>($tag=='attachment')?NULL:true));
} else
{
$temp_tpl=do_template('ATTACHMENT_DOWNLOAD',map_keys_to_upper($attachment)+array('WYSIWYG_SAFE'=>($tag=='attachment')?NULL:true));
}
break;
}
return $temp_tpl;
}
sources/attachments2.php
Global_functions_attachments2.php
Function summary
|
array
|
do_comcode_attachments (LONG_TEXT original_comcode, ID_TEXT type, ID_TEXT id, boolean previewing_only, ?object connection, ?boolean insert_as_admin, ?MEMBER for_member)
|
|
void
|
_check_attachment_count ()
|
|
integer
|
insert_lang_comcode_attachments (integer level, LONG_TEXT text, ID_TEXT type, ID_TEXT id, ?object connection, boolean insert_as_admin, ?MEMBER for_member)
|
|
void
|
final_attachments_from_preview (ID_TEXT id, ?object connection)
|
array do_comcode_attachments(LONG_TEXT original_comcode, ID_TEXT type, ID_TEXT id, boolean previewing_only, ?object connection, ?boolean insert_as_admin, ?MEMBER for_member)
Get an array containing new comcode, and tempcode. The function wraps the normal comcode_to_tempcode function. The function will do attachment management, including deleting of attachments that have become unused due to editing of some comcode and removing of the reference.
Parameters…
| Name |
original_comcode |
| Description |
The unparsed comcode that references the attachments |
| Type |
LONG_TEXT |
| Name |
type |
| Description |
The type the attachment will be used for (e.g. download) |
| Type |
ID_TEXT |
| Name |
id |
| Description |
The ID the attachment will be used for |
| Type |
ID_TEXT |
| Name |
previewing_only |
| Description |
Whether we are only previewing the attachments (i.e. don't store them!) |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
connection |
| Description |
The database connection to use (NULL: standard site connection) |
| Default value |
|
| Type |
?object |
| Name |
insert_as_admin |
| Description |
Whether to insert it as an admin (any comcode parsing will be carried out with admin privileges) (NULL: autodetect) |
| Default value |
|
| Type |
?boolean |
| Name |
for_member |
| Description |
The member to use for ownership permissions (NULL: current member) |
| Default value |
|
| Type |
?MEMBER |
Returns…
| Description |
A map containing 'comcode' (after substitution for tying down the new attachments) and 'tempcode' |
| Type |
array |
function do_comcode_attachments($original_comcode,$type,$id,$previewing_only=false,$connection=NULL,$insert_as_admin=NULL,$for_member=NULL)
{
require_lang('comcode');
global $COMCODE_ATTACHMENTS;
unset($COMCODE_ATTACHMENTS[$id]); // In case we have some kind of conflict
if (is_null($connection)) $connection=$GLOBALS['SITE_DB'];
if ($for_member!==NULL)
{
$member=$for_member;
} else
{
if (function_exists('get_member'))
{
$member=get_member();
if (is_null($insert_as_admin)) $insert_as_admin=false;
} else
{
$member=0;
if (is_null($insert_as_admin)) $insert_as_admin=true;
}
}
$comcode_text=(substr($original_comcode,0,8)!='<comcode');
// Handle data URLs for attachment embedding
if (function_exists('imagecreatefromstring'))
{
$matches=array();
$matches2=array();
$num_matches=preg_match_all('#<img (alt="" )?src="data:image/\w+;base64,([^"]*)" (title="" )?/?'.'>#',$original_comcode,$matches);
$num_matches2=preg_match_all('#\[img param=""\]data:image/\w+;base64,([^"]*)\[/img\]#',$original_comcode,$matches2);
for ($i=0;$i<$num_matches2;$i++)
{
$matches[0][$num_matches]=$matches2[0][$i];
$matches[1][$num_matches]=$matches2[1][$i];
$num_matches++;
}
for ($i=0;$i<$num_matches;$i++)
{
if (strpos($original_comcode,$matches[0][$i])!==false) // Check still here (if we have same image in multiple places, may have already been attachment-ified)
{
$data=@base64_decode($matches[1][$i]);
if ($data!==false)
{
$image=imagecreatefromstring($data);
do
{
$new_filename=uniqid('').'.png';
$new_path=get_custom_file_base().'/uploads/attachments/'.$new_filename;
}
while (file_exists($new_path));
imagepng($image,$new_path);
$attachment_id=$GLOBALS['SITE_DB']->query_insert('attachments',array(
'a_member_id'=>get_member(),
'a_file_size'=>strlen($data),
'a_url'=>'uploads/attachments/'.$new_filename,
'a_thumb_url'=>'',
'a_original_filename'=>basename($new_filename),
'a_num_downloads'=>0,
'a_last_downloaded_time'=>time(),
'a_description'=>'',
'a_add_time'=>time()),true);
$GLOBALS['SITE_DB']->query_insert('attachment_refs',array('r_referer_type'=>$type,'r_referer_id'=>$id,'a_id'=>$attachment_id));
$original_comcode=str_replace($original_comcode,$matches[0][$i],'[attachment type="inline" thumb="0"]'.strval($attachment_id).'[/attachment]');
}
}
}
}
global $ATTACHMENTS_ALREADY_REFERENCED;
$old_already=$ATTACHMENTS_ALREADY_REFERENCED;
$ATTACHMENTS_ALREADY_REFERENCED=array();
$before=$connection->query_select('attachment_refs',array('a_id','id'),array('r_referer_type'=>$type,'r_referer_id'=>$id));
foreach ($before as $ref)
{
$ATTACHMENTS_ALREADY_REFERENCED[$ref['a_id']]=1;
}
$has_one=false;
$may_have_one=false;
foreach($_POST as $key=>$value)
{
if (preg_match('#^hidFileID\_#i',$key)!=0)
{
require_code('uploads');
$may_have_one=is_swf_upload();
}
}
if ($may_have_one)
{
require_code('uploads');
is_swf_upload(true);
}
$myfile=mixed();
foreach ($_FILES as $key=>$file)
{
$matches=array();
if ((($may_have_one) && (is_swf_upload()) || (is_uploaded_file($file['tmp_name']))) && (preg_match('#file(\d+)#',$key,$matches)!=0))
{
$has_one=true;
$atype=post_param('attachmenttype'.$matches[1],'');
if (substr($atype,-8)=='_extract')
{
require_code('uploads');
require_code('files');
require_code('files2');
$thumb=(strpos($original_comcode,' thumb="1"]new_'.$matches[1].'[/attachment_safe]')!==false) || (strpos($original_comcode,' thumb="1">new_'.$matches[1].'</attachment_safe>')!==false) || (strpos($original_comcode,' thumb="1"]new_'.$matches[1].'[/attachment]')!==false) || (strpos($original_comcode,' thumb="1">new_'.$matches[1].'</attachment>')!==false);
$arcext=get_file_extension($_FILES[$key]['name']);
if (($arcext=='tar') || ($arcext=='zip'))
{
if ($arcext=='tar')
{
require_code('tar');
$myfile=tar_open($file['tmp_name'],'rb');
$dir=tar_get_directory($myfile,true);
} elseif ($arcext=='zip')
{
if ((!function_exists('zip_open')) && (get_option('unzip_cmd')=='')) warn_exit(do_lang_tempcode('ZIP_NOT_ENABLED'));
if (!function_exists('zip_open'))
{
require_code('m_zip');
$mzip=true;
} else $mzip=false;
$myfile=zip_open($file['tmp_name']);
if (is_integer($myfile))
{
require_code('failure');
warn_exit(zip_error($myfile,$mzip));
}
$dir=array();
while (($zip_entry=zip_read($myfile))!==false)
{
$dir[]=array(
'zip_entry'=>$zip_entry,
'path'=>zip_entry_name($zip_entry),
'size'=>zip_entry_filesize($zip_entry),
);
}
}
if (count($dir)>100)
{
require_code('site');
attach_message(do_lang_tempcode('TOO_MANY_FILES_TO_EXTRACT'),'warn');
} else
{
foreach ($dir as $entry)
{
$_file=preg_replace('#\..*\.#','.',basename($entry['path']));
if (!check_extension($_file,false,NULL,true)) continue;
if (should_ignore_file($entry['path'],IGNORE_ACCESS_CONTROLLERS | IGNORE_HIDDEN_FILES)) continue;
$place=get_custom_file_base().'/uploads/attachments/'.$_file;
$i=2;
// Hunt with sensible names until we don't get a conflict
while (file_exists($place))
{
$_file=strval($i).basename($entry['path']);
$place=get_custom_file_base().'/uploads/attachments/'.$_file;
$i++;
}
$i=2;
$_file_thumb=basename($entry['path']);
$place_thumb=get_custom_file_base().'/uploads/attachments_thumbs/'.$_file_thumb;
// Hunt with sensible names until we don't get a conflict
while (file_exists($place_thumb))
{
$_file_thumb=strval($i).basename($entry['path']);
$place_thumb=get_custom_file_base().'/uploads/attachments_thumbs/'.$_file_thumb;
$i++;
}
if ($arcext=='tar')
{
$file_details=tar_get_file($myfile,$entry['path'],false,$place);
} elseif ($arcext=='zip')
{
zip_entry_open($myfile,$entry['zip_entry']);
$file_details=array(
'size'=>$entry['size'],
);
$out_file=@fopen($place,'wb') OR intelligent_write_error($place);
$more=mixed();
do
{
$more=zip_entry_read($entry['zip_entry']);
if ($more!==false)
{
if (fwrite($out_file,$more)<strlen($more)) warn_exit(do_lang_tempcode('COULD_NOT_SAVE_FILE'));
}
}
while (($more!==false) && ($more!=''));
fclose($out_file);
zip_entry_close($entry['zip_entry']);
}
$description=do_lang('EXTRACTED_FILE');
if (strpos($entry['path'],'/')!==false)
{
$description=do_lang('EXTRACTED_FILE_PATH',dirname($entry['path']));
}
// Thumbnail
$thumb_url='';
require_code('images');
if (is_image($_file))
{
$gd=((get_option('is_on_gd')=='1') && (function_exists('imagetypes')));
if ($gd)
{
require_code('images');
if (!is_saveable_image($_file)) $ext='.png'; else $ext='.'.get_file_extension($_file);
$thumb_url='uploads/attachments_thumbs/'.$_file_thumb;
convert_image(get_custom_base_url().'/uploads/attachments/'.$_file,$place_thumb,-1,-1,intval(get_option('thumb_width')),true,NULL,false,true);
if ($connection->connection_write!=$GLOBALS['SITE_DB']->connection_write) $thumb_url=get_custom_base_url().'/'.$thumb_url;
} else $thumb_url='uploads/attachments/'.$_file;
}
$url='uploads/attachments/'.$_file;
if (addon_installed('galleries'))
{
require_code('images');
if ((is_video($url)) && ($connection->connection_read==$GLOBALS['SITE_DB']->connection_read))
{
require_code('transcoding');
$url=transcode_video($url,'attachments','a_url','a_original_filename',NULL,NULL);
}
}
$attachment_id=$connection->query_insert('attachments',array(
'a_member_id'=>get_member(),
'a_file_size'=>$file_details['size'],
'a_url'=>$url,
'a_thumb_url'=>$thumb_url,
'a_original_filename'=>basename($entry['path']),
'a_num_downloads'=>0,
'a_last_downloaded_time'=>time(),
'a_description'=>$description,
'a_add_time'=>time()),true);
$connection->query_insert('attachment_refs',array('r_referer_type'=>$type,'r_referer_id'=>$id,'a_id'=>$attachment_id));
if ($comcode_text)
{
$original_comcode.=chr(10).chr(10).'[attachment type="'.comcode_escape(str_replace('_extract','',$atype)).'" description="'.comcode_escape($description).'" thumb="'.($thumb?'1':'0').'"]'.strval($attachment_id).'[/attachment]';
} else
{
require_code('comcode_xml');
//$original_comcode.=chr(10).chr(10).'<attachment type="'.comcode_escape(str_replace('_extract','',$atype)).'" thumb="'.($thumb?'1':'0').'"><attachmentDescription>'.comcode_text__to__comcode_xml($description).'</attachmentDescription>'.strval($attachment_id).'</attachment>'; Would go in bad spot
}
}
}
if ($arcext=='tar')
{
tar_close($myfile);
} elseif ($arcext=='zip')
{
zip_close($myfile);
}
}
} else
{
if ((strpos($original_comcode,']new_'.$matches[1].'[/attachment]')===false) && (strpos($original_comcode,'>new_'.$matches[1].'</attachment>')===false) && (strpos($original_comcode,']new_'.$matches[1].'[/attachment_safe]')===false) && (strpos($original_comcode,'>new_'.$matches[1].'</attachment_safe>')===false))
{
if ((preg_match('#\]\d+\[/attachment\]#',$original_comcode)==0) && (preg_match('#>\d+</attachment>#',$original_comcode)==0)) // Attachment could have already been put through (e.g. during a preview). If we have actual ID's referenced, it's almost certainly the case.
{
if ($comcode_text)
{
$original_comcode.=chr(10).chr(10).'[attachment]new_'.$matches[1].'[/attachment]';
} else
{
//$original_comcode.=chr(10).chr(10).'<attachment>new_'.$matches[1].'</attachment>'; Would go in bad spot
}
}
}
}
}
}
global $LAX_COMCODE;
$temp=$LAX_COMCODE;
if ($has_one) $LAX_COMCODE=true; // We don't want a simple syntax error to cause us to lose our attachments
$tempcode=comcode_to_tempcode($original_comcode,$member,$insert_as_admin,60,$id,$connection,false,false,false,false,false,NULL,$for_member);
$LAX_COMCODE=$temp;
$ATTACHMENTS_ALREADY_REFERENCED=$old_already;
if ((array_key_exists($id,$COMCODE_ATTACHMENTS)) && (array_key_exists(0,$COMCODE_ATTACHMENTS[$id])))
{
$original_comcode=$COMCODE_ATTACHMENTS[$id][0]['comcode'];
}
$new_comcode=$original_comcode;
if (array_key_exists($id,$COMCODE_ATTACHMENTS))
{
$ids_present=array();
for ($i=0;$i<count($COMCODE_ATTACHMENTS[$id]);$i++)
{
$attachment=$COMCODE_ATTACHMENTS[$id][$i];
// If it's a new one, we need to change the comcode to reference the ID we made for it
if ($attachment['type']=='new')
{
$marker=$attachment['marker'];
// echo $marker.'!'.$new_comcode;
$a_id=$attachment['id'];
$old_length=strlen($new_comcode);
// Search backwards from $marker
$tag_end_start=$marker-strlen('[/'.$attachment['tag_type'].']'); // </attachment> would be correct if it is Comcode-XML, but they have the same length, so it's irrelevant
$tag_start_end=$tag_end_start;
while (($tag_start_end>1) && ($new_comcode[$tag_start_end-1]!=']') && ($new_comcode[$tag_start_end-1]!='>')) $tag_start_end--;
$param_keep=substr($new_comcode,0,$tag_start_end-1);
$end_keep=substr($new_comcode,$tag_end_start);
if ($comcode_text)
{
$new_comcode=$param_keep;
if (strpos(substr($param_keep,strrpos($param_keep,'[')),' type=')===false) $new_comcode.=' type="'.comcode_escape($attachment['attachmenttype']).'"';
if (strpos(substr($param_keep,strrpos($param_keep,'[')),' description=')===false) $new_comcode.=' description="'.comcode_escape($attachment['description']).'"';
$new_comcode.=']'.strval($a_id).$end_keep;
} else
{
require_code('comcode_xml');
$new_comcode=$param_keep;
if (strpos(substr($param_keep,strrpos($param_keep,'<')),' type=')===false) $new_comcode.=' type="'.comcode_escape($attachment['attachmenttype']);
$new_comcode.='">';
if (strpos(substr($param_keep,strrpos($param_keep,'<')),' description=')===false)
{
require_code('comcode_xml');
$new_comcode.='<attachmentDescription>'.comcode_text__to__comcode_xml($attachment['description'],true).'</attachmentDescription>';
}
$new_comcode.=strval($a_id).$end_keep;
}
// echo $new_comcode.'<br />!<br />';
// Update other attachment markers
$dif=strlen($new_comcode)-$old_length;
for ($j=$i+1;$j<count($COMCODE_ATTACHMENTS[$id]);$j++)
{
// echo $COMCODE_ATTACHMENTS[$id][$i]['marker'].'!';
$COMCODE_ATTACHMENTS[$id][$j]['marker']+=$dif;
}
if (!is_null($type))
$connection->query_insert('attachment_refs',array('r_referer_type'=>$type,'r_referer_id'=>$id,'a_id'=>$a_id));
} else
{
// (Re-)Reference it
$connection->query_delete('attachment_refs',array('r_referer_type'=>$type,'r_referer_id'=>$id,'a_id'=>$attachment['id']),'',1);
$connection->query_insert('attachment_refs',array('r_referer_type'=>$type,'r_referer_id'=>$id,'a_id'=>$attachment['id']));
}
$ids_present[]=$attachment['id'];
}
if (!$previewing_only)
{
// Clear any de-referenced attachments
foreach ($before as $ref)
{
if ((!in_array($ref['a_id'],$ids_present)) && (strpos($new_comcode,'attachment.php?id=')===false) && (!multi_lang()))
{
// Delete reference (as it's not actually in the new comcode!)
$connection->query_delete('attachment_refs',array('id'=>$ref['id']),'',1);
// Was that the last reference to this attachment? (if so -- delete attachment)
$test=$connection->query_value_null_ok('attachment_refs','id',array('a_id'=>$ref['a_id']));
if (is_null($test))
{
require_code('attachments3');
_delete_attachment($ref['a_id'],$connection);
}
}
}
}
}
return array(
'comcode'=>$new_comcode,
'tempcode'=>$tempcode
);
}
void _check_attachment_count()
Check that not too many attachments have been uploaded for the member submitting.
Parameters…
(No return value)
function _check_attachment_count()
{
if ((get_forum_type()=='ocf') && (function_exists('get_member')))
{
require_code('ocf_groups');
require_lang('ocf');
require_lang('comcode');
$max_attachments_per_post=ocf_get_member_best_group_property(get_member(),'max_attachments_per_post');
$may_have_one=false;
foreach($_POST as $key=>$value)
{
if (preg_match('#^hidFileID\_#i',$key)!=0)
{
require_code('uploads');
$may_have_one=is_swf_upload();
}
}
if ($may_have_one)
{
require_code('uploads');
is_swf_upload(true);
}
foreach (array_keys($_FILES) as $name)
{
if ((substr($name,0,4)=='file') && (is_numeric(substr($name,4)) && ($_FILES[$name]['tmp_name']!='')))
{
$max_attachments_per_post--;
}
}
if ($max_attachments_per_post<0) warn_exit(do_lang_tempcode('TOO_MANY_ATTACHMENTS'));
}
}
integer insert_lang_comcode_attachments(integer level, LONG_TEXT text, ID_TEXT type, ID_TEXT id, ?object connection, boolean insert_as_admin, ?MEMBER for_member)
Insert some comcode content that may contain attachments, and return the language id.
Parameters…
| Name |
level |
| Description |
The level of importance this language string holds |
| Type |
integer |
| Values restricted to |
1 2 3 4 |
| Name |
text |
| Description |
The comcode content |
| Type |
LONG_TEXT |
| Name |
type |
| Description |
The arbitrary type that the attached is for (e.g. download) |
| Type |
ID_TEXT |
| Name |
id |
| Description |
The id in the set of the arbitrary types that the attached is for |
| Type |
ID_TEXT |
| Name |
connection |
| Description |
The database connection to use (NULL: standard site connection) |
| Default value |
|
| Type |
?object |
| Name |
insert_as_admin |
| Description |
Whether to insert it as an admin (any comcode parsing will be carried out with admin privileges) |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
for_member |
| Description |
The member to use for ownership permissions (NULL: current member) |
| Default value |
|
| Type |
?MEMBER |
Returns…
| Description |
The language id |
| Type |
integer |
function insert_lang_comcode_attachments($level,$text,$type,$id,$connection=NULL,$insert_as_admin=false,$for_member=NULL)
{
if (is_null($connection)) $connection=$GLOBALS['SITE_DB'];
require_lang('comcode');
_check_attachment_count();
$_info=do_comcode_attachments($text,$type,$id,false,$connection,$insert_as_admin,$for_member);
$text2=$_info['tempcode']->to_assembly();
$member=(function_exists('get_member'))?get_member():$GLOBALS['FORUM_DRIVER']->get_guest_id();
$lang_id=NULL;
if (user_lang()=='Gibb') // Debug code to help us spot language layer bugs. We expect &keep_lang=EN to show EnglishEnglish content, but otherwise no EnglishEnglish content.
{
$lang_id=$connection->query_insert('translate',array('source_user'=>$member,'broken'=>0,'importance_level'=>$level,'text_original'=>'EnglishEnglishWarningWrongLanguageWantGibberishLang','text_parsed'=>'','language'=>'EN'),true);
}
if (is_null($lang_id))
{
$lang_id=$connection->query_insert('translate',array('source_user'=>$member,'broken'=>0,'importance_level'=>$level,'text_original'=>$_info['comcode'],'text_parsed'=>$text2,'language'=>user_lang()),true);
} else
{
$connection->query_insert('translate',array('id'=>$lang_id,'source_user'=>$member,'broken'=>0,'importance_level'=>$level,'text_original'=>$_info['comcode'],'text_parsed'=>$text2,'language'=>user_lang()));
}
final_attachments_from_preview($id,$connection);
return $lang_id;
}
void final_attachments_from_preview(ID_TEXT id, ?object connection)
Finalise attachments which were created during a preview, so that they have the proper reference IDs.
Parameters…
| Name |
id |
| Description |
The ID in the set of the arbitrary types that the attached is for |
| Type |
ID_TEXT |
| Name |
connection |
| Description |
The database connection to use (NULL: standard site connection) |
| Default value |
|
| Type |
?object |
(No return value)
function final_attachments_from_preview($id,$connection=NULL)
{
if (is_null($connection)) $connection=$GLOBALS['SITE_DB'];
// Clean up the any attachments added at the preview stage
$posting_ref_id=post_param_integer('posting_ref_id',NULL);
if ($posting_ref_id<0) fatal_exit(do_lang_tempcode('INTERNAL_ERROR'));
if (!is_null($posting_ref_id))
{
$connection->query_delete('attachment_refs',array('r_referer_type'=>'null','r_referer_id'=>strval(-$posting_ref_id)),'',1);
$connection->query_delete('attachment_refs',array('r_referer_id'=>strval(-$posting_ref_id))); // Can trash this, was made during preview but we made a new one in do_comcode_attachments (recalled by insert_lang_comcode_attachments)
}
}
0 reviews: Unrated (average)
There have been no comments yet