if (@txpinterface == 'admin') { global $smd_at_event, $smd_at_fullev, $smd_at_adm_event, $smd_at_privs, $smd_core_themes, $smd_at_prefs, $prefs, $smd_at_feedurl, $smd_at_theme_repo, $smd_at_styles; $smd_at_event = 'smd_at'; $smd_at_fullev = 'smd_admin_themes'; $smd_at_adm_event = 'smd_admat'; $smd_at_privs = '1'; $smd_at_feedurl = 'http://textgarden.org/admin-themes-feed'; $smd_at_theme_repo = 'http://textgarden.org/administration-themes'; $smd_at_styles = array( 'common' => '.smd_clear { clear:both; } .smd_smallprint { font-size:75%; text-align:center; margin-top:-12px; } .smd_hidden { display:none; margin:5px; }', 'control' => '#smd_control { margin:0 auto; } #smd_control td .publish { margin-left:50px; } #smd_control .upload-form { padding:0; } .smd_at_update { font-weight:bold; color:#990000; }', 'edit' => '#smd_at_images { margin:0px 6px -4px 0; } .smd_skin_filetypes { margin:12px 0; }', 'grid' => '.smd_grid { width:960px; margin:0 auto; } .smd_cell { float:left; padding:10px; margin:10px; border:1px ridge #ccc; width:{tw}px; height:{th}px; } .smd_cell.active { border:1px solid red; } .smd_cell:hover { background:#e2dfce; color:#80551e; } .smd_cell:hover a { color:black; } .smd_auth,.smd_actions { text-align:center; margin:5px 0; }', 'list' => '.smd_at_list tr.active, .smd_at_list tr.active a { background-color:#e2dfce; color:#80551e; }', 'setup' => '.smd_fakebtn { color:#555; cursor:pointer; } #smd_at_radio input { float:left; clear:both; } #smd_at_radio label { float:left; }', ); // Thumbnail dimensions $smd_core_themes = array('classic','remora'); add_privs($smd_at_event, $smd_at_privs); add_privs('plugin_prefs.'.$smd_at_fullev, $smd_at_privs); register_tab("extensions", $smd_at_event, smd_at_gTxt('tab_name')); register_callback('smd_at_options', 'plugin_prefs.'.$smd_at_fullev); register_callback('smd_at_welcome', 'plugin_lifecycle.'.$smd_at_fullev); register_callback('smd_at', $smd_at_event); register_callback('smd_at_per', 'admin_side', 'theme_name'); register_callback('smd_at_link', 'prefs_ui', 'theme_name'); register_callback('smd_at_upload_form', $smd_at_event.'_ui', 'upload_form'); if (isset($prefs['smd_at_system']) && $prefs['smd_at_system'] == 2) { add_privs($smd_at_adm_event, '2,3,4,5,6'); register_tab("admin", $smd_at_adm_event, smd_at_gTxt('skinner')); register_callback('smd_admat', $smd_at_adm_event); } // Double array: 1st is a list of current prefs and their defaults, // 2nd is a list of legacy prefs that may need removing in future (defaults: all empty) $smd_at_prefs = array( array( 'smd_at_case_sort' => '1', 'smd_at_crush' => 'zip', 'smd_at_tw' => '260', 'smd_at_th' => '150', 'smd_at_filename_format' => '{theme}', 'smd_at_layout' => '1', 'smd_at_system' => '0', 'smd_at_global_skin' => '', 'smd_at_group_list' => '', 'smd_at_user_list' => '', ), array( 'smd_at_file_path' => '', ) ); } // ------------------------ function smd_at($event, $step) { if(!$step or !in_array($step, array( 'smd_at_clone', 'smd_at_delete', 'smd_at_delete_image', 'smd_at_edit', 'smd_at_export', 'smd_at_import', 'smd_at_newfile', 'smd_at_prefs_install', 'smd_at_prefs_remove', 'smd_at_prefs_update', 'smd_at_rename', 'smd_at_save', 'smd_at_setup', 'smd_at_switch', 'smd_at_upload_image', 'smd_at_change_pageby', ))) { smd_at_list(''); } else $step(); } // ------------------------------------------------------------- function smd_at_welcome($event, $step) { $msg = ''; switch ($step) { case 'installed': smd_at_prefs_install(0); break; case 'deleted': smd_at_prefs_remove(0); break; } return $msg; } // ------------------------------------------------------------- function smd_at_link() { global $smd_at_event; return href(smd_at_gTxt('manage_lbl'), '?event='.$smd_at_event); } // A stub that can be called without a $message function smd_at_display() { smd_at_list(''); } // ------------------------ function smd_at_list($message='') { global $smd_at_event, $prefs, $smd_at_prefs, $theme, $smd_core_themes, $smd_at_fullev, $smd_at_feedurl, $smd_at_theme_repo, $smd_at_styles; $at_prefs = smd_at_get_prefs(); extract(gpsa(array('step', 'page', 'crit', 'search_method', 'skin'))); $message = ($message) ? $message : gps('message'); $layout = (isset($at_prefs['smd_at_layout'])) ? $at_prefs['smd_at_layout'] : 1; $stylerule = ($layout==0) ? 'list' : 'grid'; $tw = (isset($at_prefs['smd_at_tw']) ? $at_prefs['smd_at_tw'] : $smd_at_prefs[0]['smd_at_tw']) + 10; $th = (isset($at_prefs['smd_at_th']) ? $at_prefs['smd_at_th'] : $smd_at_prefs[0]['smd_at_th']) + 80; $stylereps = array( '{tw}' => $tw, '{th}' => $th, ); $helpLink = "?event=plugin&step=plugin_help&name=$smd_at_fullev#usage"; $pageby = (gps('qty')) ? gps('qty') : ((cs('smd_at_pageby')) ? cs('smd_at_pageby') : 15); $max_file_size = 150 * 1024; // a bit arbitrary! $curr_skin = (smd_at_exists($theme->name)) ? $theme->name : 'classic'; $skin_list = smd_at_read_skins(); $crushers = smd_at_crush_options(); $uncrushers = smd_at_crush_options('import'); $bases = array(); // Get a list of ancestor themes (i.e. dependencies) foreach ($skin_list as $skina) { $manifest = smd_at_read_skinfo($skina); if ($manifest) { if ($manifest['based_on']) { $bases[] = $manifest['based_on']; } } } $bases = array_unique($bases); pagetop(smd_at_gTxt('manage_lbl'),$message); // Handle paging $total = count($skin_list); $limit = max(@$pageby, 15); list($page, $offset, $numPages) = pager($total, $limit, $page); $skin_list = array_slice($skin_list, $offset, $limit); $qs = array( "event" => $smd_at_event, "page" => $page, ); echo << function smd_getcrush(skin) { skinHandle = "crush_"+skin; jQuery('.smd_popup').each(function() { box = jQuery(this); if (box.attr("id") == skinHandle) { if (box.css("display") == "none") { box.slideDown('fast'); } else { box.slideUp('fast'); } } else { box.slideUp('fast'); } }); jQuery('#'+skinHandle+' a').click(function() { jQuery(this).attr("href", "?event={$smd_at_event}&skin="+skin+"&step=smd_at_export&crush="+jQuery('#'+skinHandle+' input[type=\'radio\']:checked').val()+"&page="+{$page}); }); return false; } function smd_getval(skin, step) { skinHandle = "pop_"+skin; jQuery('.smd_popup').each(function() { box = jQuery(this); if (box.attr("id") == skinHandle) { if (box.css("display") == "none") { box.slideDown('fast'); jQuery('#'+skinHandle+' input').focus(); } else { box.slideUp('fast'); } } else { box.slideUp('fast'); } }); jQuery('#'+skinHandle+' a').click(function() { jQuery(this).attr("href", "?event={$smd_at_event}&skin="+((skin=='new')? '' : skin)+"&step="+step+"&new_skin="+jQuery('#'+skinHandle+' input').val()+"&page="+{$page}); }); jQuery('#'+skinHandle+' input').keyup(function () { this.value = this.value.replace(/[^a-zA-Z0-9_\x7f-\xff]/g,''); while (this.value.length > 0 && this.value.substring(0,1).match(/[0-9]/)) { this.value = this.value.substring(1); } }); return false; } EOJS; // Inject styles echo ''; // List the available skins echo startTable('smd_control','','',5); echo tr( tda(upload_form(smd_at_gTxt('install_skin'), '', 'smd_at_import', $smd_at_event, '', $max_file_size).br.'
'.smd_at_gTxt('supported_import', array('{types}' => join(', ', $uncrushers))).'
', ' colspan="2"') .tda(form(fInput('submit', 'submit', smd_at_gTxt('setup'), 'publish').sInput('smd_at_setup').eInput($smd_at_event)),' colspan="6" style="border:0;height:50px"') ); echo endTable(); echo '
'; $newbtn = ' '.''.smd_at_gTxt('new').'' . '
'.smd_at_gTxt('new_skin').' ['.smd_at_gTxt('confirm').']
'; $repobtn = ' '.''.smd_at_gTxt('find_theme').''; $hdrow = hed(smd_at_gTxt('list_title'). ' '. smd_at_gTxt('help_link', array('{link}' => $helpLink)), 3); if ($layout=="0") { echo startTable('list','','smd_at_list',5); echo tr( tda($hdrow.$repobtn.$newbtn, ' colspan="7"') ); echo tr( assHead( smd_at_gTxt('skin_gbl'), 'author', gTxt('version'), 'description', smd_at_gTxt('actions') ) ); } else { echo '
'.$hdrow.$repobtn.$newbtn.'
'; } if( is_callable('fsockopen') ) $transport = 'fsock'; elseif( is_callable('curl_init') ) { $transport = 'curl'; } else { $transport = ''; } $feed = ''; switch ($transport) { case 'curl': $c = curl_init(); curl_setopt($c, CURLOPT_URL, $smd_at_feedurl); curl_setopt($c, CURLOPT_REFERER, hu); curl_setopt($c, CURLOPT_RETURNTRANSFER, true); curl_setopt($c, CURLOPT_VERBOSE, false); curl_setopt($c, CURLOPT_TIMEOUT, 10); $feed = curl_exec($c); break; case 'fsock': $url = parse_url($smd_at_feedurl); $fp = @fsockopen ($url['host'], 80, $errno, $errstr, 5); if ($fp) { $qry = 'GET '.$smd_at_feedurl; $qry .= " HTTP/1.0\r\n\r\n"; fputs($fp, $qry); stream_set_timeout($fp, 10); $info = stream_get_meta_data($fp); $hdrs = true; while ((!feof($fp)) && (!$info['timed_out'])) { $line = fgets($fp, 8192); $line = preg_replace("[\r\n]", "", $line); if ($hdrs == false) { $feed .= $line."\n"; } if (strlen($line) == 0) $hdrs = false; } if ($info['timed_out']) { $feed = ''; } fclose($fp); } else { $feed = ''; } break; default: $feed = ''; } $smd_at_vlast = ''; $feeds = array(); if (isset($prefs['smd_at_versions']) && isset($prefs['smd_at_vlast'])) { if (time() - $prefs['smd_at_vlast'] < 86400) { // Last updated within the last day, so read the cached version numbers $feeds = unserialize($prefs['smd_at_versions']); } } if (!$feeds || gps('read_versions')) { $feeds = smd_at_feed($feed); $installed_feed = array(); $feeds = (is_array($feeds)) ? $feeds : array(); // Only record the version info from themes that are installed foreach($skin_list as $skin_name) { $feed_skin_name = str_replace('_', '-', $skin_name); // Unsanitize the url_title if (array_key_exists($feed_skin_name, $feeds)) { $installed_feed[$feed_skin_name] = $feeds[$feed_skin_name]; } } set_pref('smd_at_vlast', time(), $smd_at_event, PREF_HIDDEN, 'text_input'); set_pref('smd_at_versions', serialize($installed_feed), $smd_at_event, PREF_HIDDEN, 'text_input'); } foreach ($skin_list as $skin_name) { // Read each manifest and set up the labels $skinfo = smd_at_read_skinfo($skin_name); $feed_skin_name = str_replace('_', '-', $skin_name); // Unsanitize for url_title matching $thumbnail = smd_at_get_thumb($skinfo, 1); $this_skin = ($skinfo) ? (($skin_name == $curr_skin) ? strong($skinfo['dname']) : $skinfo['dname']) : $skin_name; $is_gbl = (isset($at_prefs['smd_at_global_skin']) && $skin_name == $at_prefs['smd_at_global_skin']) ? smd_at_gTxt('is_global') : ''; $thumrow = ''.$this_skin.$is_gbl.(($skinfo && $skinfo['based_on']) ? smd_at_gTxt('based_on', array('{skin}' => $skinfo['based_on'])) : '').(($thumbnail) ? '
'.$thumbnail.'
' : '').'
'; $authrow = (($skinfo && strpos($skinfo['author_uri'], "http://") === 0) ? ''.$skinfo['author'].'' : (($skinfo) ? $skinfo['author'] : '-')); $actrow = '['.gTxt('edit').']' . ' ' .(($skinfo) ? '['.smd_at_gTxt('clone').']' : '') . ' ' .(($skinfo) ? '['.smd_at_gTxt('export').']' : '') . ' ' .((in_array($skin_name, $smd_core_themes) || in_array($skin_name, $bases)) ? '' : '['.gTxt('delete').']') . '
'.smd_at_gTxt('new_cloneskin').'  ['.strong(smd_at_gTxt('confirm')).']
' . '
'.smd_at_gTxt('crush_format').''.radioSet($crushers, $skin_name.'_crush', ((isset($at_prefs['smd_at_crush'])) ? $at_prefs['smd_at_crush'] : '') ).' ['.strong(smd_at_gTxt('confirm')).']
'; $verow = ($skinfo) ? ((isset($feeds[$feed_skin_name]) && isset($feeds[$feed_skin_name]['summary']) && version_compare($feeds[$feed_skin_name]['summary'],$skinfo['version'])===1) ? ''.smd_at_gTxt('version').$skinfo['version'].'' : smd_at_gTxt('version').$skinfo['version']) : ''; if ($layout==0) { echo tr( td($thumrow) .td($authrow, 100) .td($verow) .td((($skinfo)? $skinfo['description'] : '-').(($skinfo && $skinfo['help']) ? ' '.href('['.gTxt('help').']', $skinfo['help']) : ''), 250) .td($actrow,260) , (($skin_name == $curr_skin) ? ' class="active"' : '') ); } else { echo '
'; echo '
'.$thumrow.'
'; echo '
'.$verow.smd_at_gTxt('by').$authrow.'
'; echo '
'.$actrow.'
'; echo '
'; } } if ($layout=="0") { echo ''; echo endTable(); } else { echo '
'; } echo '
'; echo n.nav_form($smd_at_event, $page, $numPages, NULL, NULL, NULL, NULL); echo n.pageby_form($smd_at_event, $pageby); } function smd_at_feed($feed) { global $feeds; $feed=preg_replace("/>"."[[:space:]]+"."<", $feed); // Kill whitespace in feed $xmlparser = xml_parser_create(); xml_set_element_handler($xmlparser, "smd_at_feed_start_tag", "smd_at_feed_end_tag"); xml_set_character_data_handler($xmlparser, "smd_at_feed_tag_contents"); xml_parse($xmlparser, $feed); xml_parser_free($xmlparser); return $feeds; } function smd_at_feed_start_tag($parser, $name, $attribs) { global $smd_at_feedin, $smd_at_feedtag; if ($name == "ENTRY") { $smd_at_feedin = true; } if ($smd_at_feedin) { $smd_at_feedtag = $name; } } function smd_at_feed_end_tag($parser, $name) { global $smd_at_feedin, $smd_at_feedtag, $smd_at_feedname; if ($name == "ENTRY") { $smd_at_feedin = false; $smd_at_feedname = ''; } } function smd_at_feed_tag_contents($parser, $data) { global $smd_at_feedin, $smd_at_feedtag, $smd_at_feedname, $feeds; if ($smd_at_feedin) { if ($smd_at_feedtag == "NAME") { $feeds[$data] = ''; $smd_at_feedname = $data; } if (isset($feeds[$smd_at_feedname])) { if ($smd_at_feedtag == "TITLE" || $smd_at_feedtag == "SUMMARY" || $smd_at_feedtag == "UPDATED" || $smd_at_feedtag == "ID" || $smd_at_feedtag == "LINK") { $feeds[$smd_at_feedname][strtolower($smd_at_feedtag)] = $data; } } } } // ------------------------ // Remove hard spaces in the upload_form so Opera and IE wrap the buttons function smd_at_upload_form($event, $step, $data, $args) { return str_replace(' ', ' ', $data); } // ------------------------ function smd_at_edit($message='') { global $smd_at_event, $smd_at_styles; extract(doSlash(gpsa(array('skin', 'new_skin', 'file')))); $at_prefs = smd_at_get_prefs(); $layout = (isset($at_prefs['smd_at_layout'])) ? $at_prefs['smd_at_layout'] : 1; $editable = array("ssc", "css", "js", "php"); $imagable = array("jpg", "jpeg", "gif", "png"); $max_file_size = 2 * 1024 * 1024; $skinfo = smd_at_read_skinfo($skin); $file = (empty($new_skin)) ? $file : $new_skin; $files = smd_at_listdir(THEME.$skin); sort($files); // Split the list into its directory groups $allfiles = array(); foreach ($files as $currfile) { $file_info = pathinfo($currfile); // Ignore any rogue Subversion files if (strpos($file_info['dirname'], '/.svn') === false) { $file_type = (isset($file_info['extension'])) ? $file_info['extension'] : 'other'; $allfiles[$file_type][] = $currfile; } } if (gps('smd_at_edits')) { $contents = str_replace('\r\n',' ',gps('smd_at_edits')); // newline workaround } else { $contents = ''; if ($file && file_exists(THEME.$skin.DS.$file)) { $contents = file(THEME.$skin.DS.$file); $contents = join("", $contents); } } // Begin rendering the page pagetop(smd_at_gTxt('edit_lbl'),$message); echo ''; $skin_list = smd_at_read_skins(); // selectInput needs both index and value to be the same in this case $skinsel = array(); foreach($skin_list as $key1 => $value1) { $skinsel[$value1] = $skin_list[$key1]; } $skinChange = '
' . eInput($smd_at_event) . sInput('smd_at_edit') . selectInput('skin', $skinsel, $skin, 0, 1) . '
'; $fileList = hed(smd_at_gTxt('skin_files'),2) . $skinChange . startTable('list', 'left', 'smd_skin_filetypes'); $fileList .= '
'.smd_at_gTxt('new_file').''; $fileList .= ' '.smd_at_gTxt((($layout=="0") ? 'skin_list' : 'skin_grid')).'
'; $others = array(); foreach ($editable as $filetype) { if (isset($allfiles[$filetype])) { foreach ($allfiles[$filetype] as $idx => $currfile) { if ($idx == 0) { $fileList .= tr(td(hed(smd_at_gTxt($filetype),3))); } $justfile = basename($currfile); $basefile = array_shift(explode ('.',$justfile)); $edit = ''.(($file == $justfile) ? strong($justfile) : $justfile).''; $del = ($basefile == $skin) ? '' : dLink($smd_at_event, 'smd_at_delete', 'file', $justfile, 1, 'skin', $skin); $fileList .= tr(td($edit).td($del)); } } else { // Some other file type if (!$others) { foreach ($allfiles as $ftype => $fls) { if (!in_array($ftype, array_merge($editable, $imagable))) { foreach ($allfiles[$ftype] as $idx => $currfile) { $justfile = basename($currfile); $basefile = array_shift(explode ('.',$justfile)); $edit = ''.(($file == $justfile) ? strong($justfile) : $justfile).''; $del = ($basefile == $skin) ? '' : dLink($smd_at_event, 'smd_at_delete', 'file', $justfile, 1, 'skin', $skin); $others[] = tr(td($edit).td($del)); } } } } } } $fileList .= ($others) ? tr(td(hed(smd_at_gTxt('other_files'),3))). join(n, $others) : ''; $fileList .= endTable(); // Make the list of images for this skin $qs = array( "event" => $smd_at_event, "step" => 'smd_at_delete_image', ); $sel[] = '
'; $sel[] = ''; $sel[] = dLink($smd_at_event, 'smd_at_delete_image', 'skin', $skin, 1); $sel[] = '
'; $sel = join('',$sel); // Image portion $imgbit = hed(smd_at_gTxt('skin_images'), 2) . startTable('list', 'left'); $imgbit .= tr(td($sel)); $imgbit .= tr(td(upload_form(smd_at_gTxt('upload_image'), '', 'smd_at_upload_image', $smd_at_event, $skin, $max_file_size, '', ''), 150)); $imgbit .= endTable(); // Render the rest of the page echo startTable('edit'). tr( tdtl($imgbit). td( hed((($skinfo) ? $skinfo['dname'] : $skin),1). form( ''.br .''.br .fInput('submit','',gTxt('save'),'publish') .eInput($smd_at_event).sInput('smd_at_save') .hInput('skin',$skin) .hInput('file',$file) ) ). tdtl($fileList) ). endTable(); } // ------------------------ // Just clear out the var so the save function treats the content as a new file function smd_at_newfile() { $_POST['file'] = ''; $message=''; smd_at_edit($message); } // ------------------------ function smd_at_clone() { global $txp_user; extract(doSlash(gpsa(array('skin', 'new_skin')))); $msg=''; $new_skin = trim($new_skin); $new_skin = rawurlencode($new_skin); if (empty($new_skin)) { $msg = smd_at_gTxt('name_empty'); } // Check the new name isn't already in use $themes = smd_at_read_skins(); if (in_array($new_skin, $themes)) { $msg = smd_at_gTxt('skin_exists', array('{name}' => $new_skin)); } // No errors, so make a new dir and create the PHP file if ($msg=='') { $content = ''; $destdir = THEME.$new_skin.DS; $res = mkdir($destdir); $based = ''; if ($skin) { // Based on an existing theme. No need for any functions other than manifest() $based = "theme::based_on('".$skin."');"; $extends = $skin.'_theme'; $srcss = THEME.$skin.DS.'textpattern.css'; if (file_exists($srcss) && filesize($srcss) > 0) { $import = join('', file($srcss)); } else { $import = '@import url("../classic/textpattern.css");'; } $content = '{'; } else { // Brand spanking new theme. Clone 'classic' functions then add new manifest() $extends = 'theme'; $import = ''; $src = txpath.DS.THEME.'classic'.DS.'classic.php'; $grab = false; $fp = file($src); foreach($fp as $line) { $line = rtrim($line); if (strpos($line, 'function manifest()') !== false) { $grab = false; // unnecessary? break; } if ($grab) { $content .= $line.n; } if (strpos($line, 'class classic_theme extends theme') !== false) { $grab = true; } } } // manifest fields $manuser = get_author_name($txp_user); $mantitle = ucwords($new_skin); // Write the new PHP file $buf = << '{$mantitle}', 'author' => '{$manuser}', 'author_uri' => '', 'version' => '1.0', 'description' => '', 'help' => '', ); } } ?> EOF; $fp = fopen($destdir.$new_skin.'.php', "wb"); fwrite($fp, $buf); fclose($fp); // Create the CSS file $fp = fopen($destdir.'textpattern.css', "wb"); fwrite($fp, $import); fclose($fp); if ($skin) { $msg = smd_at_gTxt('skin_cloned', array('{name}' => $new_skin));; } else { $msg = smd_at_gTxt('skin_created', array('{name}' => $new_skin));; } // $msg = smd_at_gTxt('skin_not_created', array('{name}' => $new_skin));; } smd_at_list($msg); } // ------------------------ function smd_at_crush_options($direction='export') { $smd_crushers = array('tar' => smd_at_gTxt('c_tar')); if ($direction == 'export') { if (function_exists('gzcompress') && function_exists('gzopen') && function_exists('gzwrite')) { $smd_crushers['gzip'] = smd_at_gTxt('c_gzip'); $smd_crushers['zip'] = smd_at_gTxt('c_zip'); } if (function_exists('bzcompress') && function_exists('bzopen') && function_exists('bzwrite')) { $smd_crushers['bzip2'] = smd_at_gTxt('c_bzip2'); } } else { // Import function requirements if (function_exists('gzinflate')) { $smd_crushers['gzip'] = smd_at_gTxt('c_gzip'); $smd_crushers['zip'] = smd_at_gTxt('c_zip'); } if (function_exists('bzdecompress')) { $smd_crushers['bzip2'] = smd_at_gTxt('c_bzip2'); } } return $smd_crushers; } // ------------------------ function smd_at_export() { global $prefs, $smd_at_prefs; extract(doSlash(gpsa(array('skin','crush')))); $message=''; chdir(THEME); $skinfo = smd_at_read_skinfo($skin); $reps = array( '{theme}' => $skin, '{version}' => $skinfo['version'], ); $out = strtr(get_pref('smd_at_filename_format', $smd_at_prefs[0]['smd_at_filename_format']), $reps); // Check the passed compression format is valid; use default if not $crushers = smd_at_crush_options(); if ($crush=='' || $crush=='undefined' || !array_key_exists($crush, $crushers)) { $crush = get_pref('smd_at_crush', $smd_at_prefs[0]['smd_at_crush']); } switch($crush) { case 'zip': $zip = new smd_at_zip_file($out.'.zip'); break; case 'bzip2': $zip = new smd_at_bzip_file($out.'.tbz2'); break; case 'tar': $zip = new smd_at_tar_file($out.'.tar'); break; case 'gzip': default: $zip = new smd_at_gzip_file($out.'.tgz'); break; } $zip->set_options(array('basedir' => txpath.DS.THEME, 'overwrite' => 1, 'inmemory' => 1)); $zip->add_files($skin.DS.'*.*'); $zip->exclude_files($skin.DS.'*.svn*'); $zip->create_archive(); $zip->download_file(); } // ------------------------ function smd_at_import() { global $prefs; $name = $_FILES['thefile']['name']; $file = get_uploaded_file($_FILES['thefile']['tmp_name'], txpath.DS.THEME.basename($_FILES['thefile']['tmp_name'])); $basedir = txpath.DS.THEME; $uncrushers = smd_at_crush_options('import'); $message=''; $info = explode ('.',$name); $lastpart = count($info)-1; $ext = $info[$lastpart]; if ($name && $file) { if ($ext == 'zip' && array_key_exists('zip', $uncrushers)) { $zip = new smd_dUnzip2($file); // $zip->debug = true; $zip->getList(); $validArchive = smd_at_check_archive($zip->compressedList, $ext); if ($validArchive) { $zip->unzipAll($basedir); $zip->close(); $message = smd_at_gTxt('import_ok'); } else { $message = array(smd_at_gTxt('import_failed'), E_WARNING); } } else if ($ext == 'tgz' && array_key_exists('gzip', $uncrushers)) { $zip = new smd_at_gzip_file(basename($file)); $zip->set_options(array('basedir' => $basedir, 'overwrite' => 1)); $zip->extract_files(); $message = smd_at_gTxt('import_ok'); } else if ($ext == 'tbz2' && array_key_exists('bzip2', $uncrushers)) { $zip = new smd_at_bzip_file(basename($file)); $zip->set_options(array('basedir' => $basedir, 'overwrite' => 1)); $zip->extract_files(); $message = smd_at_gTxt('import_ok'); } else if ($ext == 'tar') { $zip = new smd_at_tar_file(basename($file)); $zip->set_options(array('basedir' => $basedir, 'overwrite' => 1)); $zip->extract_files(); $message = smd_at_gTxt('import_ok'); } else { $message = array(smd_at_gTxt('unsupported_compressiontype', array('{crush}' => $ext)), E_WARNING); } // Remove the temporary file unlink($file); } else { $message = smd_at_gTxt('empty_info'); } smd_at_list($message); } // Check the directory structure of the archive for various items/attributes. // Each time one of the conditions is met, the vcnt is incrememented. // Once the whole archive has been read, if the vcnt matches the expectedCounts for // that type, the archive is valid. function smd_at_check_archive($struct, $type='zip') { $expectedCounts = array('zip' => 1, 'tgz' => 0, 'tbz2' => 0, 'tar' => 0); switch ($type) { case "zip": $vcnt = 0; foreach ($struct as $entry => $info) { $parts = pathinfo($info['file_name']); if (isset($parts['extension']) && $parts['extension'] == 'php') { $dirbits = explode(DS, $parts['dirname']); $numdirs = count($dirbits); if (($parts['filename'] == $dirbits[$numdirs-1]) && $numdirs==1) { $vcnt++; } } } break; } return ($expectedCounts[$type] == $vcnt) ? true : false; } // ------------------------ function smd_at_upload_image() { global $file_max_upload_size; extract(doSlash(gpsa(array('id')))); $_POST['skin'] = $skin = $id; $name = $_FILES['thefile']['name']; $file = get_uploaded_file($_FILES['thefile']['tmp_name']); $message=''; if ($file === false) { $message = gTxt('file_upload_failed') ." $name - ".upload_get_errormsg($_FILES['thefile']['error']); smd_at_edit($message); exit(); } $size = filesize($file); if ($file_max_upload_size < $size) { unlink($file); $message = gTxt('file_upload_failed') ." $name - ".upload_get_errormsg(UPLOAD_ERR_FORM_SIZE); smd_at_edit($message); exit(); } $skinfo = smd_at_read_skinfo($skin); $new_skin = $skinfo['name']; $newpath = $skinfo['path']; if ($new_skin && $file) { if(shift_uploaded_file($file, $newpath.$name)) { $message = smd_at_gTxt('upload_success'); } else { unlink($file); $message = smd_at_gTxt('upload_failed'); } } else { $message = smd_at_gTxt('empty_info'); } smd_at_edit($message); } // ------------------------ function smd_at_delete_image() { global $smd_core_themes; extract(doSlash(gpsa(array('skin')))); $file_list = gps('smd_at_images'); $message=''; if (empty($file_list)) { $message = smd_at_gTxt('empty_info'); } else { if (in_array($skin, $smd_core_themes)) { $message = smd_at_gTxt('core_theme_file', array('{skin}' => $skin)); } else { foreach ($file_list as $image) { $path = txpath.DS.$image; unlink($path); } } } smd_at_edit($message); } // ------------------------ function smd_at_delete() { global $smd_core_themes, $theme, $smd_at_privs, $smd_at_event; extract(doSlash(gpsa(array('skin', 'file')))); $message=''; if ($file) { // Editing a skin, thus deleting a single file if (in_array($skin, $smd_core_themes)) { $message = smd_at_gTxt('core_theme_file', array('{skin}' => $skin)); smd_at_edit($message); } else { $del = unlink(THEME.$skin.DS.$file); if ($del) { $message = gTxt('file_deleted', array('{name}' => $file)); $_POST['file'] = ''; // Clear the variable so the filename doesn't appear on the edit page } else { $message = smd_at_gTxt('file_not_deleted', array('{name}' => $file)); } } smd_at_edit($message); } else { if (in_array($skin, $smd_core_themes)) { $message = smd_at_gTxt('core_theme', array('{skin}' => $skin)); smd_at_list($message); } else { // Viewing the skin list, thus deleting the whole skin $skindir = THEME.$skin; if (!smd_rmdir_recursive($skindir)) { $message = smd_at_gTxt('delete_failed'); } else { $message = smd_at_gTxt('skin_deleted', array('{name}' => $skin)); } // Handle situations if current skin has been deleted if (!file_exists(txpath.DS.THEME.$skin)) { $at_prefs = smd_at_get_prefs(); // Reset the global skin in case it's been deleted $gbl_skin = (isset($at_prefs['smd_at_global_skin'])) ? $at_prefs['smd_at_global_skin'] : ''; $gbl_skin = ($gbl_skin != '' && file_exists(txpath.DS.THEME.$gbl_skin)) ? $gbl_skin : 'classic'; set_pref('smd_at_global_skin', $gbl_skin, $smd_at_event, PREF_HIDDEN, 'text_input'); set_pref('theme_name', $gbl_skin); $skin = get_pref('smd_skin'); if (!file_exists(txpath.DS.THEME.$skin)) { $skin = $gbl_skin; } set_pref('smd_skin', $skin, 'smd_at', PREF_HIDDEN, 'text_input', 0, PREF_PRIVATE); } $_GET['skin'] = $skin; $_GET['nextstep'] = 'smd_at_list'; smd_at_switch($message); } } } // ------------------------ function smd_at_save() { extract(doSlash(gpsa(array('skin','new_skin','file','smd_at_edits')))); $editable = array("ssc", "css", "js", "php"); $message = $extraMsg = ''; $file = trim($file); $new_skin = trim($new_skin); $msglev = 0; // New file if (!$file && $new_skin) { $file = $new_skin; $ext = array_pop(explode ('.',$file)); if (strtolower($file) != 'readme' && ($ext == '' || !in_array($ext, $editable))) { $message = smd_at_gTxt('unsupported_filetype').smd_at_gTxt('unsupported_fudge'); $msglev = E_WARNING; $_POST['file'] = $file; } } if ($message=='') { $fname = sanitizeForFile($file); $new_skin = rawurlencode($new_skin); $_POST['new_skin'] = $new_skin; $smd_at_edits = doStrip(str_replace('\r\n',' ',$smd_at_edits)); // newline workaround if ($fname) { $filepath = THEME.$skin.DS; if (!file_exists($filepath.$fname)) { $ret = touch($filepath.$fname); if ($ret === false) { $message = smd_at_gTxt('mkdir_failed', array('{name}' => $fname)); } } // Assuming no errors so far... if ($message == '') { $fh = fopen($filepath.$fname, 'wb'); fwrite($fh, $smd_at_edits); fclose($fh); if ($fname != $new_skin) { // Rename the file $res = rename($filepath.$fname, $filepath.$new_skin); // If the renamed file is the theme's PHP file, try to rename the main skin dir too $filebits = explode('.', $new_skin); $oldfilebits = explode('.', $fname); $ext = array_pop($filebits); if ($res && $ext == 'php' && ($oldfilebits[0] == $skin)) { $new_filepath = THEME.$filebits[0].DS; $ren = rename($filepath, $new_filepath); $filepath = ($ren) ? $new_filepath : $filepath; $_POST['skin'] = $filebits[0]; } $extraMsg = ($res) ? smd_at_gTxt('renamed', array('{name}' => $new_skin)) : smd_at_gTxt('rename_failed'); } // Process any css replacements $filebits = explode ('.',(($fname==$new_skin)? $fname : $new_skin)); $cssfile = $filebits[0]; $ext = array_pop($filebits); if ($ext == 'ssc') { $replacements = array(); $num_rep1 = preg_match_all('/(\@[A-Za-z0-9_]+):\s*(.*);/', $smd_at_edits, $matches1); $num_rep2 = preg_match_all('/(\@[A-Za-z0-9_]+):\s*\{(.*?)\}/s', $smd_at_edits, $matches2); // Simple replacements foreach($matches1 as $idx => $reparr) { if ($idx == 0) { // Remove the var definitions foreach ($reparr as $rep) { $smd_at_edits = str_replace($rep, '',$smd_at_edits); } } if ($idx == 1) { foreach ($reparr as $jdx => $rep) { $replacements[$rep] = $matches1[2][$jdx]; } } } // Multi-line replacements foreach($matches2 as $idx => $reparr) { if ($idx == 0) { // Remove the var definitions foreach ($reparr as $rep) { $smd_at_edits = str_replace($rep, '',$smd_at_edits); } } if ($idx == 1) { foreach ($reparr as $jdx => $rep) { $replacements[$rep.';'] = trim($matches2[2][$jdx]); } } } // Generate and write the new css file $smd_at_edits = trim(strtr($smd_at_edits, $replacements)); $fh = fopen($filepath.$cssfile.'.css', 'wb'); fwrite($fh, $smd_at_edits); fclose($fh); if ($fname != $new_skin) { $oldfname = explode ('.', $fname); $oldfname = $oldfname[0].'.css'; $res = @unlink($filepath.$oldfname); } } $message = smd_at_gTxt('file_saved', array('{name}' => $fname)).br.$extraMsg; } } } smd_at_edit(array($message, $msglev)); } // ------------------------ // PREFS // ------------------------ function smd_at_get_prefs() { global $smd_at_prefs; $prefkeys = doQuote(implode("','",array_keys($smd_at_prefs[0]))); $rs = safe_rows('name,val','txp_prefs','name in ('.$prefkeys.')'); $at_prefs = array(); foreach ($rs as $prefarr) { $at_prefs[$prefarr['name']] = $prefarr['val']; } return $at_prefs; } // ------------------------ function smd_at_options($event, $step, $message='') { smd_at_setup($message); } // ------------------------ function smd_at_setup($message='') { global $prefs, $smd_at_prefs, $smd_at_event, $theme, $smd_core_themes, $smd_at_styles; $numReqPrefs = count($smd_at_prefs[0]); $at_prefs = smd_at_get_prefs(); $numRows = count($at_prefs); pagetop(gTxt('prefs'),$message); // TODO: use get_groups(); $levels = array( // 1 => gTxt('publisher'), 2 => gTxt('managing_editor'), 3 => gTxt('copy_editor'), 4 => gTxt('staff_writer'), 5 => gTxt('freelancer'), 6 => gTxt('designer'), ); $numLevs = count($levels); // Split the user skin list $uskins = array(); if (isset($at_prefs['smd_at_user_list'])) { $uskins = explode(',', $at_prefs['smd_at_user_list']); } $layout = (isset($at_prefs['smd_at_layout'])) ? $at_prefs['smd_at_layout'] : 1; $clrBtn = ' ['.smd_at_gTxt('clear').']'; $btnSet = fInput('submit', 'submit', smd_at_gTxt('set'), 'publish'); $btnSave = fInput('submit', 'submit', gTxt('save'), 'publish'); $btnInstall = '
'.fInput('submit', 'submit', gTxt('install'), 'publish').'
'; $btnRemove = '
'.fInput('submit', 'submit', gTxt('delete'), 'smallerbox').'
'; $btnList = ' '.smd_at_gTxt((($layout=="0") ? 'skin_list' : 'skin_grid')).'
'; $btnStyle = ' style="border:0;height:25px"'; $radBtns = array( smd_at_gTxt('per_site'), smd_at_gTxt('per_group'), smd_at_gTxt('per_user'), ); echo startTable('list'); if ($numRows == $numReqPrefs) { // Prefs all installed $skin_list = smd_at_read_skins(); // selectInput needs both index and value to be the same in this case $skinsel = array(); foreach($skin_list as $key1 => $value1) { if (smd_at_exists($value1)) { $skinsel[$value1] = $skin_list[$key1]; } } $gbl_skin = (isset($at_prefs['smd_at_global_skin']) && $at_prefs['smd_at_global_skin'] != '') ? $at_prefs['smd_at_global_skin'] : $theme->name; echo tr(tda(strong(smd_at_gTxt('prefs_title')), ' colspan="2"') . tda($btnRemove.$btnList, $btnStyle) ); echo '
'; echo tr(tda(smd_at_gTxt('case_sort')).tda(yesnoRadio('smd_at_case_sort', $at_prefs['smd_at_case_sort']), ' width="240" id="smd_at_case_sort"')); echo tr(tda(smd_at_gTxt('crush_type')).tda(radioSet(smd_at_crush_options(), 'smd_at_crush', $at_prefs['smd_at_crush']), ' width="240" id="smd_at_crush"')); echo tr(tda(smd_at_gTxt('layout')).tda(radioSet(array(smd_at_gTxt('layout_list'), smd_at_gTxt('layout_grid')), 'smd_at_layout', $at_prefs['smd_at_layout']), ' width="240" id="smd_at_layout"')); echo tr(tda(smd_at_gTxt('thumbsize')).tda(fInput('text', 'smd_at_tw', $at_prefs['smd_at_tw'],'','','',4).smd_at_gTxt('times').fInput('text', 'smd_at_th', $at_prefs['smd_at_th'],'','','',4))); echo tr(tda(smd_at_gTxt('filename_format')).tda(fInput('text', 'smd_at_filename_format', $at_prefs['smd_at_filename_format']))); echo tr( td(smd_at_gTxt('global_skin')) .td(selectInput('smd_at_global_skin', $skinsel, $gbl_skin, 0, 0)) ); echo tr(tda(smd_at_gTxt('skin_system')).tda(radioSet($radBtns, 'smd_at_system', $at_prefs['smd_at_system']), ' width="240" id="smd_at_radio"')); // Option 1 $priv_list = ''; // Note the hidden skin group box; jQuery keeps track of any list changes and keeps it updated $sela = smd_at_gTxt('skin_groups'); $selb = hInput('smd_at_group_list', $at_prefs['smd_at_group_list']); $selb .= ''; echo tr(tda($sela, ' class="smd_at_sel1 smd_hidden"') . tda($selb.$priv_list, ' width="400" class="smd_at_sel1 smd_hidden"')); // Option 2 $sela = smd_at_gTxt('allowed_skins'); $selb = ''.$clrBtn; echo tr(tda($sela, ' class="smd_at_sel2 smd_hidden"') . tda($selb, ' width="240" class="smd_at_sel2 smd_hidden"')); echo tr(tda($btnSave, $btnStyle)); echo '
'; } else if ($numRows > 0 && $numRows < $numReqPrefs) { echo tr(tda(strong(smd_at_gTxt('prefs_some')).br.br .smd_at_gTxt('prefs_some_explain').br.br .smd_at_gTxt('prefs_some_options'), ' colspan="2"')); echo tr(tda($btnRemove,$btnStyle) . tda($btnInstall, $btnStyle)); } else { echo tr(tda(smd_at_gTxt('prefs_not_installed'), ' colspan="2"')); echo tr(tda($btnInstall, $btnStyle)); } echo endTable(); echo << // Concatenate checkbox options for storage function smd_at_prefswap(selValue) { for (idx=0; idx < 3; idx++) { if (idx==selValue) { jQuery(".smd_at_sel"+idx).show(); } else { jQuery(".smd_at_sel"+idx).hide(); } } } jQuery(function() { jQuery("input[name='smd_at_system']").change(function() { smd_at_prefswap(this.value); }); jQuery('#smd_clr').click(function() { jQuery('#smd_at_user_list option').attr("selected", ""); }); jQuery("#smd_at_grps").change(function() { selskin = jQuery(this).val(); // Clear the old privs list and grab the current list from the hidden field jQuery("#smd_at_privs option").attr("selected",false); var grplist = jQuery("input[name='smd_at_group_list']").val(); var grps = grplist.split(','); var cnt = grps.length; for (var idx = 0; idx < cnt; idx++) { privs = grps[idx].split(':'); skinid = privs.shift(); if (skinid == selskin) { numPrivs = privs.length; for (jdx = 0; jdx < numPrivs; jdx++) { jQuery("#smd_at_privs option[value='"+privs[jdx]+"']").attr("selected", true); } } } }); jQuery("#smd_at_privs").change(function() { selskin = jQuery("#smd_at_grps option:selected").val(); var out = []; var privs = []; privs.push(selskin); jQuery("#smd_at_privs option:selected").each(function() { privs.push(jQuery(this).val()); }); if (privs.length == 1) { privs.pop(); } else { out.push(privs.join(":")); } var hidlist = jQuery("input[name='smd_at_group_list']").val(); var prevlist = hidlist.split(','); var prevcnt = prevlist.length; jQuery("#smd_at_grps option").each(function() { currskin = jQuery(this).val(); if (currskin != selskin) { for (var idx = 0; idx < prevcnt; idx++) { prevprivs = prevlist[idx].split(':'); skinid = prevprivs.shift(); // Generate the priv list for the currently selected skin, removing any duplicate privs set elsewhere if (skinid == currskin) { tmpout = []; tmpout.push(skinid); for (thispriv in prevprivs) { if (jQuery.inArray(prevprivs[thispriv], privs) < 0) { tmpout.push(prevprivs[thispriv]); } } if (tmpout.length > 1) { out.push(tmpout.join(":")); } } } } }); jQuery("input[name='smd_at_group_list']").val(out); }); // Display a tooltip showing the currently-assigned skin when hovering over a privilege level jQuery("#smd_at_privs option").hover(function() { hovitem = jQuery(this).val(); grps = jQuery("input[name='smd_at_group_list']").val(); items = grps.split(","); for (idx = 0; idx < items.length; idx++) { skinz = items[idx].split(":"); for (jdx = 1; jdx < skinz.length; jdx++) { if (skinz[jdx] == hovitem) { jQuery(this).attr("title", skinz[0]); break; } } } }, function() { jQuery(this).attr("title", ""); }); smd_at_prefswap(jQuery("input[name='smd_at_system']:checked").val()); jQuery("#smd_at_privs").change(); }); EOJS; echo ''; } // ------------------------ // Split a multi-char preference value into an array of keys/values. // Note: value is passed in and not read directly from the prefs array in this function - intentionally function smd_at_pref_explode($val) { $order = array_values(array(smd_at_gTxt('c_gzip'),smd_at_gTxt('c_bzip'),smd_at_gTxt('c_zip'))); $onoff = array_values(preg_split('//', $val, -1, PREG_SPLIT_NO_EMPTY)); $out = array(); foreach($order as $key1 => $value1) { $out[(string)$value1] = $onoff[$key1]; } return $out; } // ------------------------------------------------------------- function smd_at_prefs_install($showpane='1') { global $smd_at_prefs; $message = ''; foreach ($smd_at_prefs[0] as $pref => $dflt) { if (!fetch('name','txp_prefs','name',$pref)) { $id = safe_insert('txp_prefs','prefs_id=1, name='.doQuote(doSlash($pref)).', val='.doQuote(doSlash($dflt)).',event="smd_adskin"'); } } if ($showpane) { $message = smd_at_gTxt('prefs_installed'); smd_at_setup($message); } } // ------------------------------------------------------------- function smd_at_prefs_remove($showpane='1') { global $smd_at_prefs; $message = ''; foreach (array_merge($smd_at_prefs[0],$smd_at_prefs[1]) as $pref => $dflt) { if (fetch('name','txp_prefs','name',$pref)) { $id = safe_delete('txp_prefs','name='.doQuote(doSlash($pref))); } } if ($showpane) { $message = smd_at_gTxt('prefs_deleted'); smd_at_setup($message); } } // ------------------------------------------------------------- function smd_at_prefs_update() { global $smd_plugin_prefs, $smd_at_prefs, $smd_at_event; $message = ''; $post = array(); $post['smd_at_global_skin'] = gps('smd_at_global_skin'); $post['smd_at_system'] = gps('smd_at_system'); $post['smd_at_layout'] = gps('smd_at_layout'); $post['smd_at_case_sort'] = gps('smd_at_case_sort'); $post['smd_at_tw'] = gps('smd_at_tw'); $post['smd_at_th'] = gps('smd_at_th'); $post['smd_at_filename_format'] = gps('smd_at_filename_format'); if (gps('smd_at_user_list')) { $post['smd_at_user_list'] = join(',', gps('smd_at_user_list')); } else { $post['smd_at_user_list'] = ''; } if (gps('smd_at_group_list')) { $post['smd_at_group_list'] = gps('smd_at_group_list'); } if (gps('smd_at_crush')) { $post['smd_at_crush'] = gps('smd_at_crush'); } // Set the system-wide theme to the global theme if ($post['smd_at_global_skin']) { set_pref('theme_name', $post['smd_at_global_skin']); } foreach ($smd_at_prefs[0] as $pref => $dflt) { if (isset($post[$pref])) { set_pref($pref, $post[$pref], $smd_at_event, 2); } } $message = gTxt('preferences_saved'); smd_at_setup($message); } // ------------------------ // UTILITY FUNCTIONS // ------------------------ function smd_at_get_privs($user='') { global $txp_user; $user = ($user) ? $user : $txp_user; $privs = safe_field("privs", "txp_users", "name='".doSlash($user)."'"); return $privs; } // ------------------------ function smd_at_exists($name) { $instance = theme::factory($name); return $instance; } // If per-user skin support is OFF, the global skin wins. // One exception: if the user is an admin, allow the current skin to prevail so they may switch skins with impunity // and not affect the global skin function smd_at_per() { global $smd_at_privs, $prefs, $theme, $txp_user; $at_prefs = smd_at_get_prefs(); $skinSys = isset($at_prefs['smd_at_system']) ? $at_prefs['smd_at_system'] : 0; $privs = smd_at_get_privs(); $gbl_skin = (isset($at_prefs['smd_at_global_skin']) && $at_prefs['smd_at_global_skin'] != '') ? $at_prefs['smd_at_global_skin'] : ''; $gbl_skin = (smd_at_exists($gbl_skin)) ? $gbl_skin : 'classic'; switch ($skinSys) { case 0: // Global forced skin (except admins) if (!in_array($privs, explode(',', $smd_at_privs))) { return $gbl_skin; } else { // Admins $adm_skin = get_pref('smd_skin', (($gbl_skin) ? $gbl_skin : $theme->name)); return (smd_at_exists($adm_skin)) ? $adm_skin : 'classic'; } break; case 1: // Group-level forced skins if (!in_array($privs, explode(',', $smd_at_privs))) { $forceSkins = (isset($at_prefs['smd_at_group_list'])) ? $at_prefs['smd_at_group_list'] : (($gbl_skin) ? $gbl_skin : $theme->name); // Split the group skin list $gskins = array(); $gopts = explode(',', $forceSkins); foreach ($gopts as $grpdef) { if ($grpdef == '') continue; $privgrp = explode(":", $grpdef); $skinid = array_shift($privgrp); if (in_array($privs, $privgrp)) { return (smd_at_exists($skinid)) ? $skinid : 'classic';; } } return ($gbl_skin) ? $gbl_skin : $theme->name; } else { // Admins $adm_skin = get_pref('smd_skin', (($gbl_skin) ? $gbl_skin : $theme->name)); return (smd_at_exists($adm_skin)) ? $adm_skin : 'classic'; } break; case 2: // Per-user skin. If user is non-admin, check the skin is in the allowed list if (!in_array($privs, explode(',', $smd_at_privs))) { $validSkins = (isset($at_prefs['smd_at_user_list'])) ? $at_prefs['smd_at_user_list'] : (($gbl_skin) ? $gbl_skin : $theme->name); $validSkins = do_list($validSkins); $the_skin = get_pref('smd_skin', (($gbl_skin) ? $gbl_skin : $theme->name)); return (in_array($the_skin, $validSkins) && smd_at_exists($the_skin)) ? $the_skin : ''; } else { // Admins $adm_skin = get_pref('smd_skin', (($gbl_skin) ? $gbl_skin : $theme->name)); return (smd_at_exists($adm_skin)) ? $adm_skin : 'classic'; } break; } } // ------------------------ // Read and return the manifest, if it exists and add a few other niceties to the array for later function smd_at_read_skinfo($skin) { global $smd_core_themes; $this_theme = theme::factory($skin); $skinfo = array(); if ($this_theme) { $skinfo = $this_theme->manifest(); $skinfo['dname'] = empty($skinfo['title']) ? ucwords($this_theme->name) : $skinfo['title']; $skinfo['name'] = $this_theme->name; $skinfo['path'] = $this_theme->url; $skinfo['phpfile'] = $this_theme->path($skin); $skinfo['based_on'] = ''; $contents = file_get_contents($skinfo['phpfile']); if (($pos = strpos($contents, 'theme::based_on')) !== false) { $begpos = strpos($contents, "'", $pos)+1; $endpos = strpos($contents, "'", $begpos); $base = substr($contents, $begpos, $endpos-$begpos); $skinfo['based_on'] = (in_array($base, $smd_core_themes)) ? '' : $base; } unset($this_theme); } return $skinfo; } // ------------------------ // Grab the thumbnail filename if it exists, optionally return a formatted img tag function smd_at_get_thumb($skin, $img=0) { global $smd_at_prefs; $at_prefs = smd_at_get_prefs(); $tw = isset($at_prefs['smd_at_tw']) ? $at_prefs['smd_at_tw'] : $smd_at_prefs[0]['smd_at_tw']; $th = isset($at_prefs['smd_at_th']) ? $at_prefs['smd_at_th'] : $smd_at_prefs[0]['smd_at_th']; $use_thumb = ($tw == 0 || $th == 0) ? false : true; // An array means the manifest has already been read and is being passed into this function if (!is_array($skin)) { $skin = smd_at_read_skinfo($skin); } if ($skin) { $skindir = $skin['path']; $thumbname = glob($skindir.'screenshot.*'); return ($img && $use_thumb && $thumbname && file_exists($thumbname[0])) ? ''.((isset($skin['name'])) ? $skin['name'] : '').' thumbnail' : ''; } else { return ''; } } // ------------------------ function smd_at_read_skins() { $skin_list = theme::names(); $skin_list = smd_at_sort($skin_list); return $skin_list; } // Sort the skins but keep 'classic' at the top function smd_at_sort($skin_list) { global $prefs; $caseSense = isset($prefs['smd_at_case_sort']) ? $prefs['smd_at_case_sort'] : 1; if($caseSense) { natsort($skin_list); } else { natcasesort($skin_list); } $dflt_found = false; foreach ($skin_list as $skin_idx => $skin_name) { if ($skin_name == "classic") { unset($skin_list[$skin_idx]); $dflt_found = true; break; } } if ($dflt_found) { array_unshift($skin_list,"classic"); } return $skin_list; } // ------------------------ function smd_at_listdir($start_dir='.') { $files = array(); if (is_dir($start_dir)) { $fh = opendir($start_dir); while (($file = readdir($fh)) !== false) { // loop through the files, skipping . and .., and recursing if necessary if (strcmp($file, '.')==0 || strcmp($file, '..')==0) continue; $filepath = $start_dir . '/' . $file; if ( is_dir($filepath) ) { $files = array_merge($files, smd_at_listdir($filepath)); } else { array_push($files, $filepath); } } closedir($fh); } else { // false if the function was called with an invalid non-directory argument $files = false; } return $files; } // ------------------------ // Recursive rmdir() courtesy of the php manual user comments function smd_rmdir_recursive($filepath) { if (is_dir($filepath) && !is_link($filepath)) { if ($dh = opendir($filepath)) { while (($sf = readdir($dh)) !== false) { if ($sf == '.' || $sf == '..') continue; if (!smd_rmdir_recursive($filepath.'/'.$sf)) { break; // Doh, can't delete } } closedir($dh); } return rmdir($filepath); } return unlink($filepath); } // ------------------------ // From PHP manual comments. Thanks puremango function smd_at_is_dir($dir) { // bypasses open_basedir restrictions of is_dir and fileperms $tmp_cmd = `ls -dl $dir`; $dir_flag = $tmp_cmd[0]; if($dir_flag!="d") { // not d; use next char (first char might be 's' and is still directory) $dir_flag = $tmp_cmd[1]; } return ($dir_flag=="d"); } // ------------------------ function smd_mkdir_recursive($path, $mode = 0755) { if(@mkdir($path, $mode) or file_exists($path)) return true; return (smd_mkdir_recursive(dirname($path), $mode) and mkdir($path, $mode)); } // ------------------------ function smd_at_change_pageby() { setcookie('smd_at_pageby', gps('qty')); smd_at_list(''); } // ------------------------ function smd_at_switch($message='') { global $smd_at_privs; extract(doSlash(gpsa(array('skin', 'event', 'nextstep')))); $url = "?event=".$event."&step=".$nextstep; if ($skin && smd_at_exists($skin)) { set_pref('smd_skin', $skin, $event, PREF_HIDDEN, 'text_input', 0, PREF_PRIVATE); $url .= '&message=' . (($message) ? $message : smd_at_gTxt('skin_switched', array('{skin}' => $skin))); } else { $url .= '&message=' . $message; } // Since the headers have been sent, double-declutch in order to show the skin this first time echo << window.location.href="{$url}"; EOS; exit; } // All-user skin chooser function smd_admat($event, $step) { if(!$step or !in_array($step, array( 'smd_at_switch', ))) { smd_at_chooser(''); } else $step(); } // ------------------------ function smd_at_chooser($message='') { global $prefs, $smd_at_adm_event, $theme, $smd_at_styles; $at_prefs = smd_at_get_prefs(); $layout = (isset($at_prefs['smd_at_layout'])) ? $at_prefs['smd_at_layout'] : 1; $tw = (isset($at_prefs['smd_at_tw']) ? $at_prefs['smd_at_tw'] : $smd_at_prefs[0]['smd_at_tw']) + 10; $th = (isset($at_prefs['smd_at_th']) ? $at_prefs['smd_at_th'] : $smd_at_prefs[0]['smd_at_th']) + 80; $stylereps = array( '{tw}' => $tw, '{th}' => $th, ); $message = ($message) ? $message : gps('message'); pagetop(smd_at_gTxt('skinner'),$message); $curr_skin = $theme->name; $allowed = ''; if (isset($prefs['smd_at_user_list'])) { $allowed = explode(",",$prefs['smd_at_user_list']); foreach ($allowed as $idx => $valid) { if ($valid == '') { unset($allowed[$idx]); } } } $allowed = smd_at_sort($allowed); $hdrow = hed(smd_at_gTxt('avail_title'), 3); if ($layout=="0") { echo ''; echo startTable('list', '', 'smd_at_list'); echo tr( tda($hdrow, ' colspan="3"') ); echo tr( assHead( smd_at_gTxt('skin_gbl'), 'author', 'description' )); } else { echo ''; echo '
'.$hdrow.'
'; } foreach ($allowed as $skin_name) { $skinfo = smd_at_read_skinfo($skin_name); if ($skinfo) { $thumbnail = smd_at_get_thumb($skinfo, 1); $this_skin = ($skin_name == $curr_skin) ? strong($skinfo['dname']) : $skinfo['dname']; $thumrow = ''.$this_skin.(($thumbnail) ? '
'.$thumbnail.'
' : '').'
'; $authrow = (strpos($skinfo['author_uri'], "http://") === 0) ? ''.$skinfo['author'].'' : $skinfo['author']; if ($layout=="0") { echo tr( td($thumrow) .td($authrow, 100) .td($skinfo['description'], 250) , (($skin_name == $curr_skin) ? ' class="active"' : '') ); } else { echo '
'; echo '
'.$thumrow.'
'; echo '
'.smd_at_gTxt('by').$authrow.'
'; echo '
'; } } } if ($layout=="0") { echo endTable(); } else { echo '
'; } } /*-------------------------------------------------- | TAR/GZIP/BZIP2/ZIP ARCHIVE CLASSES 2.1 | By Devin Doucette | Copyright (c) 2005 Devin Doucette | Email: darksnoopy@shaw.ca +-------------------------------------------------- | Email bugs/suggestions to darksnoopy@shaw.ca +-------------------------------------------------- | This script has been created and released under | the GNU GPL and is free to use and redistribute | only if this copyright statement is not removed +--------------------------------------------------*/ // NOTE: class names altered to add smd_at_ prefix to avoid clashes in global scope, and added subdir creation class smd_at_archive { function smd_at_archive($name) { $this->options = array ( 'basedir' => ".", 'name' => $name, 'prepend' => "", 'inmemory' => 0, 'overwrite' => 0, 'recurse' => 1, 'storepaths' => 1, 'followlinks' => 0, 'level' => 3, 'method' => 1, 'sfx' => "", 'type' => "", 'comment' => "" ); $this->files = array (); $this->exclude = array (); $this->storeonly = array (); $this->error = array (); } function set_options($options) { foreach ($options as $key => $value) $this->options[$key] = $value; if (!empty ($this->options['basedir'])) { $this->options['basedir'] = str_replace("\\", "/", $this->options['basedir']); $this->options['basedir'] = preg_replace("/\/+/", "/", $this->options['basedir']); $this->options['basedir'] = preg_replace("/\/$/", "", $this->options['basedir']); } if (!empty ($this->options['name'])) { $this->options['name'] = str_replace("\\", "/", $this->options['name']); $this->options['name'] = preg_replace("/\/+/", "/", $this->options['name']); } if (!empty ($this->options['prepend'])) { $this->options['prepend'] = str_replace("\\", "/", $this->options['prepend']); $this->options['prepend'] = preg_replace("/^(\.*\/+)+/", "", $this->options['prepend']); $this->options['prepend'] = preg_replace("/\/+/", "/", $this->options['prepend']); $this->options['prepend'] = preg_replace("/\/$/", "", $this->options['prepend']) . "/"; } } function create_archive() { $this->make_list(); if ($this->options['inmemory'] == 0) { $pwd = getcwd(); chdir($this->options['basedir']); if ($this->options['overwrite'] == 0 && file_exists($this->options['name'] . ($this->options['type'] == "gzip" || $this->options['type'] == "bzip" ? ".tmp" : ""))) { $this->error[] = "File {$this->options['name']} already exists."; chdir($pwd); return 0; } else if ($this->archive = @fopen($this->options['name'] . ($this->options['type'] == "gzip" || $this->options['type'] == "bzip" ? ".tmp" : ""), "wb+")) chdir($pwd); else { $this->error[] = "Could not open {$this->options['name']} for writing."; chdir($pwd); return 0; } } else $this->archive = ""; switch ($this->options['type']) { case "zip": if (!$this->create_zip()) { $this->error[] = "Could not create zip file."; return 0; } break; case "bzip": if (!$this->create_tar()) { $this->error[] = "Could not create tar file."; return 0; } if (!$this->create_bzip()) { $this->error[] = "Could not create bzip2 file."; return 0; } break; case "gzip": if (!$this->create_tar()) { $this->error[] = "Could not create tar file."; return 0; } if (!$this->create_gzip()) { $this->error[] = "Could not create gzip file."; return 0; } break; case "tar": if (!$this->create_tar()) { $this->error[] = "Could not create tar file."; return 0; } } if ($this->options['inmemory'] == 0) { fclose($this->archive); if ($this->options['type'] == "gzip" || $this->options['type'] == "bzip") unlink($this->options['basedir'] . "/" . $this->options['name'] . ".tmp"); } } function add_data($data) { if ($this->options['inmemory'] == 0) fwrite($this->archive, $data); else $this->archive .= $data; } function make_list() { if (!empty ($this->exclude)) foreach ($this->files as $key => $value) foreach ($this->exclude as $current) if ($value['name'] == $current['name']) unset ($this->files[$key]); if (!empty ($this->storeonly)) foreach ($this->files as $key => $value) foreach ($this->storeonly as $current) if ($value['name'] == $current['name']) $this->files[$key]['method'] = 0; unset ($this->exclude, $this->storeonly); } function add_files($list) { $temp = $this->list_files($list); foreach ($temp as $current) $this->files[] = $current; } function exclude_files($list) { $temp = $this->list_files($list); foreach ($temp as $current) $this->exclude[] = $current; } function store_files($list) { $temp = $this->list_files($list); foreach ($temp as $current) $this->storeonly[] = $current; } function list_files($list) { if (!is_array ($list)) { $temp = $list; $list = array ($temp); unset ($temp); } $files = array (); $pwd = getcwd(); chdir($this->options['basedir']); foreach ($list as $current) { $current = str_replace("\\", "/", $current); $current = preg_replace("/\/+/", "/", $current); $current = preg_replace("/\/$/", "", $current); if (strstr($current, "*")) { $regex = preg_replace("/([\\\^\$\.\[\]\|\(\)\?\+\{\}\/])/", "\\\\\\1", $current); $regex = str_replace("*", ".*", $regex); $dir = strstr($current, "/") ? substr($current, 0, strrpos($current, "/")) : "."; $temp = $this->parse_dir($dir); foreach ($temp as $current2) if (preg_match("/^{$regex}$/i", $current2['name'])) $files[] = $current2; unset ($regex, $dir, $temp, $current); } else if (@is_dir($current)) { $temp = $this->parse_dir($current); foreach ($temp as $file) $files[] = $file; unset ($temp, $file); } else if (@file_exists($current)) $files[] = array ('name' => $current, 'name2' => $this->options['prepend'] . preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($current, "/")) ? substr($current, strrpos($current, "/") + 1) : $current), 'type' => @is_link($current) && $this->options['followlinks'] == 0 ? 2 : 0, 'ext' => substr($current, strrpos($current, ".")), 'stat' => stat($current)); } chdir($pwd); unset ($current, $pwd); usort($files, array ("smd_at_archive", "sort_files")); return $files; } function parse_dir($dirname) { if ($this->options['storepaths'] == 1 && !preg_match("/^(\.+\/*)+$/", $dirname)) $files = array (array ('name' => $dirname, 'name2' => $this->options['prepend'] . preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($dirname, "/")) ? substr($dirname, strrpos($dirname, "/") + 1) : $dirname), 'type' => 5, 'stat' => stat($dirname))); else $files = array (); $dir = @opendir($dirname); while ($file = @readdir($dir)) { $fullname = $dirname . "/" . $file; if ($file == "." || $file == "..") continue; else if (@is_dir($fullname)) { if (empty ($this->options['recurse'])) continue; $temp = $this->parse_dir($fullname); foreach ($temp as $file2) $files[] = $file2; } else if (@file_exists($fullname)) $files[] = array ('name' => $fullname, 'name2' => $this->options['prepend'] . preg_replace("/(\.+\/+)+/", "", ($this->options['storepaths'] == 0 && strstr($fullname, "/")) ? substr($fullname, strrpos($fullname, "/") + 1) : $fullname), 'type' => @is_link($fullname) && $this->options['followlinks'] == 0 ? 2 : 0, 'ext' => substr($file, strrpos($file, ".")), 'stat' => stat($fullname)); } @closedir($dir); return $files; } function sort_files($a, $b) { if ($a['type'] != $b['type']) if ($a['type'] == 5 || $b['type'] == 2) return -1; else if ($a['type'] == 2 || $b['type'] == 5) return 1; else if ($a['type'] == 5) return strcmp(strtolower($a['name']), strtolower($b['name'])); else if ($a['ext'] != $b['ext']) return strcmp($a['ext'], $b['ext']); else if ($a['stat'][7] != $b['stat'][7]) return $a['stat'][7] > $b['stat'][7] ? -1 : 1; else return strcmp(strtolower($a['name']), strtolower($b['name'])); return 0; } function download_file() { if ($this->options['inmemory'] == 0) { $this->error[] = "Can only use download_file() if archive is in memory. Redirect to file otherwise, it is faster."; return; } switch ($this->options['type']) { case "zip": header("Content-Type: application/zip"); break; case "bzip": header("Content-Type: application/x-bzip2"); break; case "gzip": header("Content-Type: application/x-gzip"); break; case "tar": header("Content-Type: application/x-tar"); } $header = "Content-Disposition: attachment; filename=\""; $header .= strstr($this->options['name'], "/") ? substr($this->options['name'], strrpos($this->options['name'], "/") + 1) : $this->options['name']; $header .= "\""; header($header); header("Content-Length: " . strlen($this->archive)); header("Content-Transfer-Encoding: binary"); header("Cache-Control: no-cache, must-revalidate, max-age=60"); header("Expires: Sat, 01 Jan 2000 12:00:00 GMT"); print($this->archive); } } class smd_at_tar_file extends smd_at_archive { function smd_at_tar_file($name) { $this->smd_at_archive($name); $this->options['type'] = "tar"; } function create_tar() { $pwd = getcwd(); chdir($this->options['basedir']); foreach ($this->files as $current) { if ($current['name'] == $this->options['name']) continue; if (strlen($current['name2']) > 99) { $path = substr($current['name2'], 0, strpos($current['name2'], "/", strlen($current['name2']) - 100) + 1); $current['name2'] = substr($current['name2'], strlen($path)); if (strlen($path) > 154 || strlen($current['name2']) > 99) { $this->error[] = "Could not add {$path}{$current['name2']} to archive because the filename is too long."; continue; } } $block = pack("a100a8a8a8a12a12a8a1a100a6a2a32a32a8a8a155a12", $current['name2'], sprintf("%07o", $current['stat'][2]), sprintf("%07o", $current['stat'][4]), sprintf("%07o", $current['stat'][5]), sprintf("%011o", $current['type'] == 2 ? 0 : $current['stat'][7]), sprintf("%011o", $current['stat'][9]), " ", $current['type'], $current['type'] == 2 ? @readlink($current['name']) : "", "ustar ", " ", "Unknown", "Unknown", "", "", !empty ($path) ? $path : "", ""); $checksum = 0; for ($i = 0; $i < 512; $i++) $checksum += ord(substr($block, $i, 1)); $checksum = pack("a8", sprintf("%07o", $checksum)); $block = substr_replace($block, $checksum, 148, 8); if ($current['type'] == 2 || $current['stat'][7] == 0) $this->add_data($block); else if ($fp = @fopen($current['name'], "rb")) { $this->add_data($block); while ($temp = fread($fp, 1048576)) $this->add_data($temp); if ($current['stat'][7] % 512 > 0) { $temp = ""; for ($i = 0; $i < 512 - $current['stat'][7] % 512; $i++) $temp .= "\0"; $this->add_data($temp); } fclose($fp); } else $this->error[] = "Could not open file {$current['name']} for reading. It was not added."; } $this->add_data(pack("a1024", "")); chdir($pwd); return 1; } function extract_files() { $pwd = getcwd(); chdir($this->options['basedir']); if ($fp = $this->open_archive()) { if ($this->options['inmemory'] == 1) $this->files = array (); while ($block = fread($fp, 512)) { $temp = unpack("a100name/a8mode/a8uid/a8gid/a12size/a12mtime/a8checksum/a1type/a100symlink/a6magic/a2temp/a32temp/a32temp/a8temp/a8temp/a155prefix/a12temp", $block); $file = array ( 'name' => $temp['prefix'] . $temp['name'], 'stat' => array ( 2 => $temp['mode'], 4 => octdec($temp['uid']), 5 => octdec($temp['gid']), 7 => octdec($temp['size']), 9 => octdec($temp['mtime']), ), 'checksum' => octdec($temp['checksum']), 'type' => $temp['type'], 'magic' => $temp['magic'], ); if ($file['checksum'] == 0x00000000) break; else if (substr($file['magic'], 0, 5) != "ustar") { $this->error[] = "This script does not support extracting this type of tar file."; break; } $block = substr_replace($block, " ", 148, 8); $checksum = 0; for ($i = 0; $i < 512; $i++) $checksum += ord(substr($block, $i, 1)); if ($file['checksum'] != $checksum) $this->error[] = "Could not extract from {$this->options['name']}, it is corrupt."; // Added: create dir if required if (strpos($file['name'], '..') === false) { $path_parts = pathinfo($file['name']); if (!file_exists($file['name'])) { $ret = smd_mkdir_recursive(((isset($path_parts['extension'])) ? dirname($this->options['basedir'].DS.$file['name']) : $this->options['basedir'].DS.$file['name'])); } } if ($this->options['inmemory'] == 1) { $file['data'] = fread($fp, $file['stat'][7]); fread($fp, (512 - $file['stat'][7] % 512) == 512 ? 0 : (512 - $file['stat'][7] % 512)); unset ($file['checksum'], $file['magic']); $this->files[] = $file; } else if ($file['type'] == 5) { if (!is_dir($file['name'])) mkdir($file['name'], $file['stat'][2]); } else if ($this->options['overwrite'] == 0 && file_exists($file['name'])) { $this->error[] = "{$file['name']} already exists."; continue; } else if ($file['type'] == 2) { symlink($temp['symlink'], $file['name']); chmod($file['name'], $file['stat'][2]); } else if ($new = fopen($file['name'], "wb")) { fwrite($new, fread($fp, $file['stat'][7])); fread($fp, (512 - $file['stat'][7] % 512) == 512 ? 0 : (512 - $file['stat'][7] % 512)); fclose($new); @chmod($file['name'], 0644); // Hard-coded for now because the stupid 0100644 value in $file['stat'][2] confuses the OS/PHP } else { $this->error[] = "Could not open {$file['name']} for writing."; continue; } // Remove owner and group setting since there is almost 0 likelihood the files will have the same user/group across systems // In other words, leave owner/group at the Apache default -- which is what we want // chown($file['name'], $file['stat'][4]); // chgrp($file['name'], $file['stat'][5]); @touch($file['name'], $file['stat'][9]); unset ($file); } } else $this->error[] = "Could not open file {$this->options['name']}"; chdir($pwd); } function open_archive() { return @fopen($this->options['name'], "rb"); } } class smd_at_gzip_file extends smd_at_tar_file { function smd_at_gzip_file($name) { $this->smd_at_tar_file($name); $this->options['type'] = "gzip"; } function create_gzip() { if ($this->options['inmemory'] == 0) { $pwd = getcwd(); chdir($this->options['basedir']); if ($fp = gzopen($this->options['name'], "wb{$this->options['level']}")) { fseek($this->archive, 0); while ($temp = fread($this->archive, 1048576)) gzwrite($fp, $temp); gzclose($fp); chdir($pwd); } else { $this->error[] = "Could not open {$this->options['name']} for writing."; chdir($pwd); return 0; } } else $this->archive = gzencode($this->archive, $this->options['level']); return 1; } function open_archive() { return @gzopen($this->options['name'], "rb"); } } class smd_at_bzip_file extends smd_at_tar_file { function smd_at_bzip_file($name) { $this->smd_at_tar_file($name); $this->options['type'] = "bzip"; } function create_bzip() { if ($this->options['inmemory'] == 0) { $pwd = getcwd(); chdir($this->options['basedir']); if ($fp = bzopen($this->options['name'], "wb")) { fseek($this->archive, 0); while ($temp = fread($this->archive, 1048576)) bzwrite($fp, $temp); bzclose($fp); chdir($pwd); } else { $this->error[] = "Could not open {$this->options['name']} for writing."; chdir($pwd); return 0; } } else $this->archive = bzcompress($this->archive, $this->options['level']); return 1; } function open_archive() { return @bzopen($this->options['name'], "r"); } } class smd_at_zip_file extends smd_at_archive { function smd_at_zip_file($name) { $this->smd_at_archive($name); $this->options['type'] = "zip"; } function create_zip() { $files = 0; $offset = 0; $central = ""; if (!empty ($this->options['sfx'])) if ($fp = @fopen($this->options['sfx'], "rb")) { $temp = fread($fp, filesize($this->options['sfx'])); fclose($fp); $this->add_data($temp); $offset += strlen($temp); unset ($temp); } else $this->error[] = "Could not open sfx module from {$this->options['sfx']}."; $pwd = getcwd(); chdir($this->options['basedir']); foreach ($this->files as $current) { if ($current['name'] == $this->options['name']) continue; $timedate = explode(" ", date("Y n j G i s", $current['stat'][9])); $timedate = ($timedate[0] - 1980 << 25) | ($timedate[1] << 21) | ($timedate[2] << 16) | ($timedate[3] << 11) | ($timedate[4] << 5) | ($timedate[5]); $block = pack("VvvvV", 0x04034b50, 0x000A, 0x0000, (isset($current['method']) || $this->options['method'] == 0) ? 0x0000 : 0x0008, $timedate); if ($current['stat'][7] == 0 && $current['type'] == 5) { $block .= pack("VVVvv", 0x00000000, 0x00000000, 0x00000000, strlen($current['name2']) + 1, 0x0000); $block .= $current['name2'] . "/"; $this->add_data($block); $central .= pack("VvvvvVVVVvvvvvVV", 0x02014b50, 0x0014, $this->options['method'] == 0 ? 0x0000 : 0x000A, 0x0000, (isset($current['method']) || $this->options['method'] == 0) ? 0x0000 : 0x0008, $timedate, 0x00000000, 0x00000000, 0x00000000, strlen($current['name2']) + 1, 0x0000, 0x0000, 0x0000, 0x0000, $current['type'] == 5 ? 0x00000010 : 0x00000000, $offset); $central .= $current['name2'] . "/"; $files++; $offset += (31 + strlen($current['name2'])); } else if ($current['stat'][7] == 0) { $block .= pack("VVVvv", 0x00000000, 0x00000000, 0x00000000, strlen($current['name2']), 0x0000); $block .= $current['name2']; $this->add_data($block); $central .= pack("VvvvvVVVVvvvvvVV", 0x02014b50, 0x0014, $this->options['method'] == 0 ? 0x0000 : 0x000A, 0x0000, (isset($current['method']) || $this->options['method'] == 0) ? 0x0000 : 0x0008, $timedate, 0x00000000, 0x00000000, 0x00000000, strlen($current['name2']), 0x0000, 0x0000, 0x0000, 0x0000, $current['type'] == 5 ? 0x00000010 : 0x00000000, $offset); $central .= $current['name2']; $files++; $offset += (30 + strlen($current['name2'])); } else if ($fp = @fopen($current['name'], "rb")) { $temp = fread($fp, $current['stat'][7]); fclose($fp); $crc32 = crc32($temp); if (!isset($current['method']) && $this->options['method'] == 1) { $temp = gzcompress($temp, $this->options['level']); $size = strlen($temp) - 6; $temp = substr($temp, 2, $size); } else $size = strlen($temp); $block .= pack("VVVvv", $crc32, $size, $current['stat'][7], strlen($current['name2']), 0x0000); $block .= $current['name2']; $this->add_data($block); $this->add_data($temp); unset ($temp); $central .= pack("VvvvvVVVVvvvvvVV", 0x02014b50, 0x0014, $this->options['method'] == 0 ? 0x0000 : 0x000A, 0x0000, (isset($current['method']) || $this->options['method'] == 0) ? 0x0000 : 0x0008, $timedate, $crc32, $size, $current['stat'][7], strlen($current['name2']), 0x0000, 0x0000, 0x0000, 0x0000, 0x00000000, $offset); $central .= $current['name2']; $files++; $offset += (30 + strlen($current['name2']) + $size); } else $this->error[] = "Could not open file {$current['name']} for reading. It was not added."; } $this->add_data($central); $this->add_data(pack("VvvvvVVv", 0x06054b50, 0x0000, 0x0000, $files, $files, strlen($central), $offset, !empty ($this->options['comment']) ? strlen($this->options['comment']) : 0x0000)); if (!empty ($this->options['comment'])) $this->add_data($this->options['comment']); chdir($pwd); return 1; } } ############################################################## # Class dUnzip2 v2.62 # # Author: Alexandre Tedeschi (d) # E-Mail: alexandrebr at gmail dot com # Londrina - PR / Brazil # # Objective: # This class allows programmer to easily unzip files on the fly. # # Requirements: # This class requires extension ZLib Enabled. It is default # for most site hosts around the world, and for the PHP Win32 dist. # # To do: # * Error handling # * Write a PHP-Side gzinflate, to completely avoid any external extensions # * Write other decompress algorithms # # Methods: # * dUnzip2($filename) - Constructor - Opens $filename # * getList([$stopOnFile]) - Retrieve the file list # * getExtraInfo($zipfilename) - Retrieve more information about compressed file # * getZipInfo([$entry]) - Retrieve ZIP file details. # * unzip($zipfilename, [$outfilename, [$applyChmod]]) - Unzip file # * unzipAll([$outDir, [$zipDir, [$maintainStructure, [$applyChmod]]]]) # * close() - Close file handler, but keep the list # * __destroy() - Close file handler and release memory # # If you modify this class, or have any ideas to improve it, please contact me! # You are allowed to redistribute this class, if you keep my name and contact e-mail on it. # # PLEASE! IF YOU USE THIS CLASS IN ANY OF YOUR PROJECTS, PLEASE LET ME KNOW! # If you have problems using it, don't think twice before contacting me! # ############################################################## if(!function_exists('file_put_contents')){ // If not PHP5, creates a compatible function Function file_put_contents($file, $data){ if($tmp = fopen($file, "w")){ fwrite($tmp, $data); fclose($tmp); return true; } echo "file_put_contents: Cannot create file $file
"; return false; } } class smd_dUnzip2{ Function getVersion(){ return "2.62"; } // Public var $fileName; var $lastError; var $compressedList; // You will problably use only this one! var $centralDirList; // Central dir list... It's a kind of 'extra attributes' for a set of files var $endOfCentral; // End of central dir, contains ZIP Comments var $debug; // Private var $fh; var $zipSignature = "\x50\x4b\x03\x04"; // local file header signature var $dirSignature = "\x50\x4b\x01\x02"; // central dir header signature var $dirSignatureE= "\x50\x4b\x05\x06"; // end of central dir signature // Public Function smd_dUnzip2($fileName){ $this->fileName = $fileName; $this->compressedList = $this->centralDirList = $this->endOfCentral = Array(); } Function getList($stopOnFile=false){ if(sizeof($this->compressedList)){ $this->debugMsg(1, "Returning already loaded file list."); return $this->compressedList; } // Open file, and set file handler $fh = fopen($this->fileName, "r"); $this->fh = &$fh; if(!$fh){ $this->debugMsg(2, "Failed to load file."); return false; } $this->debugMsg(1, "Loading list from 'End of Central Dir' index list..."); if(!$this->_loadFileListByEOF($fh, $stopOnFile)){ $this->debugMsg(1, "Failed! Trying to load list looking for signatures..."); if(!$this->_loadFileListBySignatures($fh, $stopOnFile)){ $this->debugMsg(1, "Failed! Could not find any valid header."); $this->debugMsg(2, "ZIP File is corrupted or empty"); return false; } } if($this->debug){ #------- Debug compressedList $kkk = 0; echo ""; foreach($this->compressedList as $fileName=>$item){ if(!$kkk && $kkk=1){ echo ""; foreach($item as $fieldName=>$value) echo ""; echo ''; } echo ""; foreach($item as $fieldName=>$value){ if($fieldName == 'lastmod_datetime') echo ""; else echo ""; } echo ""; } echo "
$fieldName
".date("d/m/Y H:i:s", $value)."$value
"; #------- Debug centralDirList $kkk = 0; if(sizeof($this->centralDirList)){ echo ""; foreach($this->centralDirList as $fileName=>$item){ if(!$kkk && $kkk=1){ echo ""; foreach($item as $fieldName=>$value) echo ""; echo ''; } echo ""; foreach($item as $fieldName=>$value){ if($fieldName == 'lastmod_datetime') echo ""; else echo ""; } echo ""; } echo "
$fieldName
".date("d/m/Y H:i:s", $value)."$value
"; } #------- Debug endOfCentral $kkk = 0; if(sizeof($this->endOfCentral)){ echo ""; echo ""; foreach($this->endOfCentral as $field=>$value){ echo ""; echo ""; echo ""; echo ""; } echo "
dUnzip - End of file
$field$value
"; } } return $this->compressedList; } Function getExtraInfo($compressedFileName){ return isset($this->centralDirList[$compressedFileName])? $this->centralDirList[$compressedFileName]: false; } Function getZipInfo($detail=false){ return $detail? $this->endOfCentral[$detail]: $this->endOfCentral; } Function unzip($compressedFileName, $targetFileName=false, $applyChmod=0777){ if(!sizeof($this->compressedList)){ $this->debugMsg(1, "Trying to unzip before loading file list... Loading it!"); $this->getList(false, $compressedFileName); } $fdetails = &$this->compressedList[$compressedFileName]; if(!isset($this->compressedList[$compressedFileName])){ $this->debugMsg(2, "File '$compressedFileName' is not compressed in the zip."); return false; } if(substr($compressedFileName, -1) == "/"){ $this->debugMsg(2, "Trying to unzip a folder name '$compressedFileName'."); return false; } if(!$fdetails['uncompressed_size']){ $this->debugMsg(1, "File '$compressedFileName' is empty."); return $targetFileName? file_put_contents($targetFileName, ""): ""; } fseek($this->fh, $fdetails['contents-startOffset']); $ret = $this->uncompress( fread($this->fh, $fdetails['compressed_size']), $fdetails['compression_method'], $fdetails['uncompressed_size'], $targetFileName ); if($applyChmod && $targetFileName) chmod($targetFileName, 0777); return $ret; } Function unzipAll($targetDir=false, $baseDir="", $maintainStructure=true, $applyChmod=0777){ if($targetDir === false) $targetDir = dirname($_SERVER['SCRIPT_FILENAME'])."/"; $lista = $this->getList(); if(sizeof($lista)) foreach($lista as $fileName=>$trash){ $dirname = dirname($fileName); $outDN = "$targetDir/$dirname"; if(substr($dirname, 0, strlen($baseDir)) != $baseDir) continue; if(!is_dir($outDN) && $maintainStructure){ $str = ""; $folders = explode("/", $dirname); foreach($folders as $folder){ $str = $str?"$str/$folder":$folder; if(!is_dir("$targetDir/$str")){ $this->debugMsg(1, "Creating folder: $targetDir/$str"); mkdir("$targetDir/$str"); if($applyChmod) chmod("$targetDir/$str", $applyChmod); } } } if(substr($fileName, -1, 1) == "/") continue; $maintainStructure? $this->unzip($fileName, "$targetDir/$fileName", $applyChmod): $this->unzip($fileName, "$targetDir/".basename($fileName), $applyChmod); } } Function close(){ // Free the file resource if($this->fh) fclose($this->fh); } Function __destroy(){ $this->close(); } // Private (you should NOT call these methods): Function uncompress(&$content, $mode, $uncompressedSize, $targetFileName=false){ switch($mode){ case 0: // Not compressed return $targetFileName? file_put_contents($targetFileName, $content): $content; case 1: $this->debugMsg(2, "Shrunk mode is not supported... yet?"); return false; case 2: case 3: case 4: case 5: $this->debugMsg(2, "Compression factor ".($mode-1)." is not supported... yet?"); return false; case 6: $this->debugMsg(2, "Implode is not supported... yet?"); return false; case 7: $this->debugMsg(2, "Tokenizing compression algorithm is not supported... yet?"); return false; case 8: // Deflate return $targetFileName? file_put_contents($targetFileName, gzinflate($content, $uncompressedSize)): gzinflate($content, $uncompressedSize); case 9: $this->debugMsg(2, "Enhanced Deflating is not supported... yet?"); return false; case 10: $this->debugMsg(2, "PKWARE Date Compression Library Impoloding is not supported... yet?"); return false; case 12: // Bzip2 return $targetFileName? file_put_contents($targetFileName, bzdecompress($content)): bzdecompress($content); case 18: $this->debugMsg(2, "IBM TERSE is not supported... yet?"); return false; default: $this->debugMsg(2, "Unknown uncompress method: $mode"); return false; } } Function debugMsg($level, $string){ if($this->debug){ if($level == 1) echo "dUnzip2: $string
"; if($level == 2) echo "dUnzip2: $string
"; } $this->lastError = $string; } Function getLastError(){ return $this->lastError; } Function _loadFileListByEOF(&$fh, $stopOnFile=false){ // Check if there's a valid Central Dir signature. // Let's consider a file comment smaller than 1024 characters... // Actually, it length can be 65536.. But we're not going to support it. for($x = 0; $x < 1024; $x++){ fseek($fh, -22-$x, SEEK_END); $signature = fread($fh, 4); if($signature == $this->dirSignatureE){ // If found EOF Central Dir $eodir['disk_number_this'] = unpack("v", fread($fh, 2)); // number of this disk $eodir['disk_number'] = unpack("v", fread($fh, 2)); // number of the disk with the start of the central directory $eodir['total_entries_this'] = unpack("v", fread($fh, 2)); // total number of entries in the central dir on this disk $eodir['total_entries'] = unpack("v", fread($fh, 2)); // total number of entries in $eodir['size_of_cd'] = unpack("V", fread($fh, 4)); // size of the central directory $eodir['offset_start_cd'] = unpack("V", fread($fh, 4)); // offset of start of central directory with respect to the starting disk number $zipFileCommentLenght = unpack("v", fread($fh, 2)); // zipfile comment length $eodir['zipfile_comment'] = $zipFileCommentLenght[1]?fread($fh, $zipFileCommentLenght[1]):''; // zipfile comment $this->endOfCentral = Array( 'disk_number_this'=>$eodir['disk_number_this'][1], 'disk_number'=>$eodir['disk_number'][1], 'total_entries_this'=>$eodir['total_entries_this'][1], 'total_entries'=>$eodir['total_entries'][1], 'size_of_cd'=>$eodir['size_of_cd'][1], 'offset_start_cd'=>$eodir['offset_start_cd'][1], 'zipfile_comment'=>$eodir['zipfile_comment'], ); // Then, load file list fseek($fh, $this->endOfCentral['offset_start_cd']); $signature = fread($fh, 4); while($signature == $this->dirSignature){ $dir['version_madeby'] = unpack("v", fread($fh, 2)); // version made by $dir['version_needed'] = unpack("v", fread($fh, 2)); // version needed to extract $dir['general_bit_flag'] = unpack("v", fread($fh, 2)); // general purpose bit flag $dir['compression_method'] = unpack("v", fread($fh, 2)); // compression method $dir['lastmod_time'] = unpack("v", fread($fh, 2)); // last mod file time $dir['lastmod_date'] = unpack("v", fread($fh, 2)); // last mod file date $dir['crc-32'] = fread($fh, 4); // crc-32 $dir['compressed_size'] = unpack("V", fread($fh, 4)); // compressed size $dir['uncompressed_size'] = unpack("V", fread($fh, 4)); // uncompressed size $fileNameLength = unpack("v", fread($fh, 2)); // filename length $extraFieldLength = unpack("v", fread($fh, 2)); // extra field length $fileCommentLength = unpack("v", fread($fh, 2)); // file comment length $dir['disk_number_start'] = unpack("v", fread($fh, 2)); // disk number start $dir['internal_attributes'] = unpack("v", fread($fh, 2)); // internal file attributes-byte1 $dir['external_attributes1']= unpack("v", fread($fh, 2)); // external file attributes-byte2 $dir['external_attributes2']= unpack("v", fread($fh, 2)); // external file attributes $dir['relative_offset'] = unpack("V", fread($fh, 4)); // relative offset of local header $dir['file_name'] = fread($fh, $fileNameLength[1]); // filename $dir['extra_field'] = $extraFieldLength[1] ?fread($fh, $extraFieldLength[1]) :''; // extra field $dir['file_comment'] = $fileCommentLength[1]?fread($fh, $fileCommentLength[1]):''; // file comment // Convert the date and time, from MS-DOS format to UNIX Timestamp $BINlastmod_date = str_pad(decbin($dir['lastmod_date'][1]), 16, '0', STR_PAD_LEFT); $BINlastmod_time = str_pad(decbin($dir['lastmod_time'][1]), 16, '0', STR_PAD_LEFT); $lastmod_dateY = bindec(substr($BINlastmod_date, 0, 7))+1980; $lastmod_dateM = bindec(substr($BINlastmod_date, 7, 4)); $lastmod_dateD = bindec(substr($BINlastmod_date, 11, 5)); $lastmod_timeH = bindec(substr($BINlastmod_time, 0, 5)); $lastmod_timeM = bindec(substr($BINlastmod_time, 5, 6)); $lastmod_timeS = bindec(substr($BINlastmod_time, 11, 5)); // Some protection agains attacks... if(!$dir['file_name'] = $this->_protect($dir['file_name'])) continue; $this->centralDirList[$dir['file_name']] = Array( 'version_madeby'=>$dir['version_madeby'][1], 'version_needed'=>$dir['version_needed'][1], 'general_bit_flag'=>str_pad(decbin($dir['general_bit_flag'][1]), 8, '0', STR_PAD_LEFT), 'compression_method'=>$dir['compression_method'][1], 'lastmod_datetime' =>mktime($lastmod_timeH, $lastmod_timeM, $lastmod_timeS, $lastmod_dateM, $lastmod_dateD, $lastmod_dateY), 'crc-32' =>str_pad(dechex(ord($dir['crc-32'][3])), 2, '0', STR_PAD_LEFT). str_pad(dechex(ord($dir['crc-32'][2])), 2, '0', STR_PAD_LEFT). str_pad(dechex(ord($dir['crc-32'][1])), 2, '0', STR_PAD_LEFT). str_pad(dechex(ord($dir['crc-32'][0])), 2, '0', STR_PAD_LEFT), 'compressed_size'=>$dir['compressed_size'][1], 'uncompressed_size'=>$dir['uncompressed_size'][1], 'disk_number_start'=>$dir['disk_number_start'][1], 'internal_attributes'=>$dir['internal_attributes'][1], 'external_attributes1'=>$dir['external_attributes1'][1], 'external_attributes2'=>$dir['external_attributes2'][1], 'relative_offset'=>$dir['relative_offset'][1], 'file_name'=>$dir['file_name'], 'extra_field'=>$dir['extra_field'], 'file_comment'=>$dir['file_comment'], ); $signature = fread($fh, 4); } // If loaded centralDirs, then try to identify the offsetPosition of the compressed data. if($this->centralDirList) foreach($this->centralDirList as $filename=>$details){ $i = $this->_getFileHeaderInformation($fh, $details['relative_offset']); $this->compressedList[$filename]['file_name'] = $filename; $this->compressedList[$filename]['compression_method'] = $details['compression_method']; $this->compressedList[$filename]['version_needed'] = $details['version_needed']; $this->compressedList[$filename]['lastmod_datetime'] = $details['lastmod_datetime']; $this->compressedList[$filename]['crc-32'] = $details['crc-32']; $this->compressedList[$filename]['compressed_size'] = $details['compressed_size']; $this->compressedList[$filename]['uncompressed_size'] = $details['uncompressed_size']; $this->compressedList[$filename]['lastmod_datetime'] = $details['lastmod_datetime']; $this->compressedList[$filename]['extra_field'] = $i['extra_field']; $this->compressedList[$filename]['contents-startOffset']=$i['contents-startOffset']; if(strtolower($stopOnFile) == strtolower($filename)) break; } return true; } } return false; } Function _loadFileListBySignatures(&$fh, $stopOnFile=false){ fseek($fh, 0); $return = false; for(;;){ $details = $this->_getFileHeaderInformation($fh); if(!$details){ $this->debugMsg(1, "Invalid signature. Trying to verify if is old style Data Descriptor..."); fseek($fh, 12 - 4, SEEK_CUR); // 12: Data descriptor - 4: Signature (that will be read again) $details = $this->_getFileHeaderInformation($fh); } if(!$details){ $this->debugMsg(1, "Still invalid signature. Probably reached the end of the file."); break; } $filename = $details['file_name']; $this->compressedList[$filename] = $details; $return = true; if(strtolower($stopOnFile) == strtolower($filename)) break; } return $return; } Function _getFileHeaderInformation(&$fh, $startOffset=false){ if($startOffset !== false) fseek($fh, $startOffset); $signature = fread($fh, 4); if($signature == $this->zipSignature){ # $this->debugMsg(1, "Zip Signature!"); // Get information about the zipped file $file['version_needed'] = unpack("v", fread($fh, 2)); // version needed to extract $file['general_bit_flag'] = unpack("v", fread($fh, 2)); // general purpose bit flag $file['compression_method'] = unpack("v", fread($fh, 2)); // compression method $file['lastmod_time'] = unpack("v", fread($fh, 2)); // last mod file time $file['lastmod_date'] = unpack("v", fread($fh, 2)); // last mod file date $file['crc-32'] = fread($fh, 4); // crc-32 $file['compressed_size'] = unpack("V", fread($fh, 4)); // compressed size $file['uncompressed_size'] = unpack("V", fread($fh, 4)); // uncompressed size $fileNameLength = unpack("v", fread($fh, 2)); // filename length $extraFieldLength = unpack("v", fread($fh, 2)); // extra field length $file['file_name'] = fread($fh, $fileNameLength[1]); // filename $file['extra_field'] = $extraFieldLength[1]?fread($fh, $extraFieldLength[1]):''; // extra field $file['contents-startOffset']= ftell($fh); // Bypass the whole compressed contents, and look for the next file fseek($fh, $file['compressed_size'][1], SEEK_CUR); // Convert the date and time, from MS-DOS format to UNIX Timestamp $BINlastmod_date = str_pad(decbin($file['lastmod_date'][1]), 16, '0', STR_PAD_LEFT); $BINlastmod_time = str_pad(decbin($file['lastmod_time'][1]), 16, '0', STR_PAD_LEFT); $lastmod_dateY = bindec(substr($BINlastmod_date, 0, 7))+1980; $lastmod_dateM = bindec(substr($BINlastmod_date, 7, 4)); $lastmod_dateD = bindec(substr($BINlastmod_date, 11, 5)); $lastmod_timeH = bindec(substr($BINlastmod_time, 0, 5)); $lastmod_timeM = bindec(substr($BINlastmod_time, 5, 6)); $lastmod_timeS = bindec(substr($BINlastmod_time, 11, 5)); // Some protection agains attacks... if(!$file['file_name'] = $this->_protect($file['file_name'])) return; // Mount file table $i = Array( 'file_name' =>$file['file_name'], 'compression_method'=>$file['compression_method'][1], 'version_needed' =>$file['version_needed'][1], 'lastmod_datetime' =>mktime($lastmod_timeH, $lastmod_timeM, $lastmod_timeS, $lastmod_dateM, $lastmod_dateD, $lastmod_dateY), 'crc-32' =>str_pad(dechex(ord($file['crc-32'][3])), 2, '0', STR_PAD_LEFT). str_pad(dechex(ord($file['crc-32'][2])), 2, '0', STR_PAD_LEFT). str_pad(dechex(ord($file['crc-32'][1])), 2, '0', STR_PAD_LEFT). str_pad(dechex(ord($file['crc-32'][0])), 2, '0', STR_PAD_LEFT), 'compressed_size' =>$file['compressed_size'][1], 'uncompressed_size' =>$file['uncompressed_size'][1], 'extra_field' =>$file['extra_field'], 'general_bit_flag' =>str_pad(decbin($file['general_bit_flag'][1]), 8, '0', STR_PAD_LEFT), 'contents-startOffset'=>$file['contents-startOffset'] ); return $i; } return false; } Function _protect($fullPath){ // Known hack-attacks (filename like): // /home/usr // ../../home/usr // folder/../../../home/usr // sample/(x0)../home/usr $fullPath = strtr($fullPath, ":*<>|\"\x0\\", "......./"); while($fullPath[0] == "/") $fullPath = substr($fullPath, 1); if(substr($fullPath, -1) == "/"){ $base = ''; $fullPath = substr($fullPath, 0, -1); } else{ $base = basename($fullPath); $fullPath = dirname($fullPath); } $parts = explode("/", $fullPath); $lastIdx = false; foreach($parts as $idx=>$part){ if($part == ".") unset($parts[$idx]); elseif($part == ".."){ unset($parts[$idx]); if($lastIdx !== false){ unset($parts[$lastIdx]); } } elseif($part === ''){ unset($parts[$idx]); } else{ $lastIdx = $idx; } } $fullPath = sizeof($parts)?implode("/", $parts)."/":""; return $fullPath.$base; } } class smd_dZip{ var $filename; var $overwrite; var $zipSignature = "\x50\x4b\x03\x04"; // local file header signature var $dirSignature = "\x50\x4b\x01\x02"; // central dir header signature var $dirSignatureE= "\x50\x4b\x05\x06"; // end of central dir signature var $files_count = 0; var $fh; Function smd_dZip($filename, $overwrite=true){ $this->filename = $filename; $this->overwrite = $overwrite; } Function addDir($dirname, $fileComments=''){ if(substr($dirname, -1) != '/') $dirname .= '/'; $this->addFile(false, $dirname, $fileComments); } Function addFile($filename, $cfilename, $fileComments='', $data=false){ if(!($fh = &$this->fh)) $fh = fopen($this->filename, $this->overwrite?'wb':'a+b'); // $filename can be a local file OR the data wich will be compressed if(substr($cfilename, -1)=='/'){ $details['uncsize'] = 0; $data = ''; } elseif(file_exists($filename)){ $details['uncsize'] = filesize($filename); $data = file_get_contents($filename); } elseif($filename){ echo "Cannot add $filename. File not found
"; return false; } else{ $details['uncsize'] = strlen($filename); // DATA is given.. use it! :| } // if data to compress is too small, just store it if($details['uncsize'] < 256){ $details['comsize'] = $details['uncsize']; $details['vneeded'] = 10; $details['cmethod'] = 0; $zdata = &$data; } else{ // otherwise, compress it $zdata = gzcompress($data); $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); // fix crc bug (thanks to Eric Mueller) $details['comsize'] = strlen($zdata); $details['vneeded'] = 10; $details['cmethod'] = 8; } $details['bitflag'] = 0; $details['crc_32'] = crc32($data); // Convert date and time to DOS Format, and set then $lastmod_timeS = str_pad(decbin(date('s')>=32?date('s')-32:date('s')), 5, '0', STR_PAD_LEFT); $lastmod_timeM = str_pad(decbin(date('i')), 6, '0', STR_PAD_LEFT); $lastmod_timeH = str_pad(decbin(date('H')), 5, '0', STR_PAD_LEFT); $lastmod_dateD = str_pad(decbin(date('d')), 5, '0', STR_PAD_LEFT); $lastmod_dateM = str_pad(decbin(date('m')), 4, '0', STR_PAD_LEFT); $lastmod_dateY = str_pad(decbin(date('Y')-1980), 7, '0', STR_PAD_LEFT); # echo "ModTime: $lastmod_timeS-$lastmod_timeM-$lastmod_timeH (".date("s H H").")\n"; # echo "ModDate: $lastmod_dateD-$lastmod_dateM-$lastmod_dateY (".date("d m Y").")\n"; $details['modtime'] = bindec("$lastmod_timeH$lastmod_timeM$lastmod_timeS"); $details['moddate'] = bindec("$lastmod_dateY$lastmod_dateM$lastmod_dateD"); $details['offset'] = ftell($fh); fwrite($fh, $this->zipSignature); fwrite($fh, pack('s', $details['vneeded'])); // version_needed fwrite($fh, pack('s', $details['bitflag'])); // general_bit_flag fwrite($fh, pack('s', $details['cmethod'])); // compression_method fwrite($fh, pack('s', $details['modtime'])); // lastmod_time fwrite($fh, pack('s', $details['moddate'])); // lastmod_date fwrite($fh, pack('V', $details['crc_32'])); // crc-32 fwrite($fh, pack('I', $details['comsize'])); // compressed_size fwrite($fh, pack('I', $details['uncsize'])); // uncompressed_size fwrite($fh, pack('s', strlen($cfilename))); // file_name_length fwrite($fh, pack('s', 0)); // extra_field_length fwrite($fh, $cfilename); // file_name // ignoring extra_field fwrite($fh, $zdata); // Append it to central dir $details['external_attributes'] = (substr($cfilename, -1)=='/'&&!$zdata)?16:32; // Directory or file name $details['comments'] = $fileComments; $this->appendCentralDir($cfilename, $details); $this->files_count++; } Function setExtra($filename, $property, $value){ $this->centraldirs[$filename][$property] = $value; } Function save($zipComments=''){ if(!($fh = &$this->fh)) $fh = fopen($this->filename, $this->overwrite?'w':'a+'); $cdrec = ""; foreach($this->centraldirs as $filename=>$cd){ $cdrec .= $this->dirSignature; $cdrec .= "\x0\x0"; // version made by $cdrec .= pack('v', $cd['vneeded']); // version needed to extract $cdrec .= "\x0\x0"; // general bit flag $cdrec .= pack('v', $cd['cmethod']); // compression method $cdrec .= pack('v', $cd['modtime']); // lastmod time $cdrec .= pack('v', $cd['moddate']); // lastmod date $cdrec .= pack('V', $cd['crc_32']); // crc32 $cdrec .= pack('V', $cd['comsize']); // compressed filesize $cdrec .= pack('V', $cd['uncsize']); // uncompressed filesize $cdrec .= pack('v', strlen($filename)); // file comment length $cdrec .= pack('v', 0); // extra field length $cdrec .= pack('v', strlen($cd['comments'])); // file comment length $cdrec .= pack('v', 0); // disk number start $cdrec .= pack('v', 0); // internal file attributes $cdrec .= pack('V', $cd['external_attributes']); // internal file attributes $cdrec .= pack('V', $cd['offset']); // relative offset of local header $cdrec .= $filename; $cdrec .= $cd['comments']; } $before_cd = ftell($fh); fwrite($fh, $cdrec); // end of central dir fwrite($fh, $this->dirSignatureE); fwrite($fh, pack('v', 0)); // number of this disk fwrite($fh, pack('v', 0)); // number of the disk with the start of the central directory fwrite($fh, pack('v', $this->files_count)); // total # of entries "on this disk" fwrite($fh, pack('v', $this->files_count)); // total # of entries overall fwrite($fh, pack('V', strlen($cdrec))); // size of central dir fwrite($fh, pack('V', $before_cd)); // offset to start of central dir fwrite($fh, pack('v', strlen($zipComments))); // .zip file comment length fwrite($fh, $zipComments); fclose($fh); } // Private Function appendCentralDir($filename,$properties){ $this->centraldirs[$filename] = $properties; } } // ------------------------ // Plugin-specific replacement strings - localise as required function smd_at_gTxt($what, $atts = array()) { $lang = array( 'actions' => 'Actions', 'allowed_skins' => 'Allowed themes:', 'apply_skin' => 'Apply this theme', 'avail_title' => 'Available themes', 'based_on' => ' (based on {skin})', 'by' => ' by ', 'c_bzip2' => 'BZip', 'c_gzip' => 'GZip', 'c_tar' => 'Tar', 'c_zip' => 'Zip', 'case_sort' => 'Case-sensitive theme list:', 'clear' => 'none', 'clone' => 'Base', 'confirm' => 'Go', 'core_theme' => 'Cannot delete {skin}: core theme', 'core_theme_file' => 'Cannot delete files from {skin}: core theme', 'crush_type' => 'Export compression type:', 'crush_format' => 'Format:', 'ssc' => 'Styleplates', 'css' => 'Styles', 'delete_confirm' => 'Really delete theme {skin}?', 'delete_failed' => 'Delete failed. Try removing it manually', 'edit_lbl' => 'Theme editor', 'empty_info' => 'You should choose a file first :-)', 'export' => 'Export', 'filename_format' => 'Filename format: ', 'file_not_deleted' => 'File {name} '.strong("not").' deleted', 'file_saved' => 'File {name} saved', 'find_theme' => 'Browse themes', 'global_skin' => 'Default theme:', 'help_link' => '(Help)', 'img' => 'Images', 'import_failed' => 'Installation failed :-( Check the archive structure', 'import_success' => 'Installation successful. Files extracted: {num}', 'import_ok' => 'Installation successful.', 'install_skin' => 'Install theme', 'invalid_file' => 'Rogue file detected: {name}', 'is_global' => ' [DEFAULT]', 'js' => 'Scripts', 'layout' => 'Layout method:', 'layout_list' => 'List', 'layout_grid' => 'Grid', 'list_title' => 'Installed themes', 'manage_lbl' => 'Theme manager', 'mkdir_failed' => 'Cannot create directory for file {name}. Try manually creating it.', 'name_empty' => 'You should give your theme a name :-)', 'new' => 'Create new theme', 'new_file' => 'New file', 'new_cloneskin' => 'Name of copy:', 'new_skin' => 'Theme name:', 'other_files' => 'Others', 'php' => 'Code', 'per_group' => 'One theme per privilege level', 'per_site' => 'One theme for everyone', 'per_user' => 'One theme per user', 'prefs_deleted' => 'Preferences deleted', 'prefs_installed' => 'Preferences installed', 'prefs_not_installed' => 'Preferences not installed.', 'prefs_some' => 'Not all preferences available.', 'prefs_some_explain' => 'It is either because this is a different version of the'.br.'plugin to one you had before or the preferences'.br.'have become corrupt somehow.', 'prefs_some_options' => 'Choose '.gTxt('delete').' to remove them all or '.gTxt('install').' to add'.br.'any new ones, leaving all existing preferences untouched.', 'prefs_title' => 'Admin theme preferences', 'rename_failed' => 'Rename failed', 'renamed' => 'Renamed to {name}', 'set' => 'Set', 'setup' => 'Preferences', 'skin_gbl' => 'Theme', 'skin_cloned' => 'Theme extended as {name}', 'skin_created' => 'Theme {name} created', 'skin_deleted' => 'Theme {name} deleted', 'skin_exists' => 'Theme {name} already exists', 'skin_files' => 'Theme files', 'skin_groups' => 'Group themes:', 'skin_images' => 'Theme images', 'skin_list' => 'Theme list', 'skin_grid' => 'Theme grid', 'skin_not_created' => 'Theme {name} could not be created. Try manually making the directory', 'skin_not_found' => 'The theme {name} could not be found', 'skin_switched' => 'Theme switched to {skin}', 'skin_system' => 'Theme system:', 'skinner' => 'Theme', 'supported_import' => 'Supported import types: {types}', 'tab_name' => 'Admin themes', 'thumbsize' => 'Thumb dimensions:', 'times' => ' x ', 'unsupported_compressiontype' => '{crush} is not a supported compression format in this installation', 'unsupported_filetype' => 'File is not of a supported type', 'unsupported_fudge' => ': hit Save again to store anyway', 'update' => 'Update', 'upload_failed' => 'Image could not be uploaded', 'upload_image' => 'Upload image', 'upload_success' => 'Image uploaded successfully', 'version' => 'v', ); return strtr($lang[$what], $atts); }