diff options
author | vdigital <vdigital@piwigo.org> | 2008-05-23 21:05:41 +0000 |
---|---|---|
committer | vdigital <vdigital@piwigo.org> | 2008-05-23 21:05:41 +0000 |
commit | 77fd1f51a3c5f5a52f72ef8a299fe368228e2285 (patch) | |
tree | a67ede42904657ccf3349ecdaef1cec8b8e36ff8 /BSF/include | |
parent | 553727dffacc48e8337c1d141f2a25af359e74b1 (diff) |
git-svn-id: http://piwigo.org/svn/trunk@2357 68402e56-0260-453c-a942-63ccdbb3a9ee
Diffstat (limited to 'BSF/include')
129 files changed, 29419 insertions, 0 deletions
diff --git a/BSF/include/calendar_base.class.php b/BSF/include/calendar_base.class.php new file mode 100644 index 000000000..bd3d2b180 --- /dev/null +++ b/BSF/include/calendar_base.class.php @@ -0,0 +1,351 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * Base class for monthly and weekly calendar styles + */ +class CalendarBase +{ + // db column on which this calendar works + var $date_field; + // used for queries (INNER JOIN or normal) + var $inner_sql; + // + var $calendar_levels; + + /** + * Initialize the calendar + * @param string inner_sql used for queries (INNER JOIN or normal) + */ + function initialize($inner_sql) + { + global $page; + if ($page['chronology_field']=='posted') + { + $this->date_field = 'date_available'; + } + else + { + $this->date_field = 'date_creation'; + } + $this->inner_sql = $inner_sql; + } + + function get_display_name() + { + global $conf, $page; + $res = ''; + + for ($i=0; $i<count($page['chronology_date']); $i++) + { + $res .= $conf['level_separator']; + if ( isset($page['chronology_date'][$i+1]) ) + { + $chronology_date = array_slice($page['chronology_date'],0, $i+1); + $url = duplicate_index_url( + array( 'chronology_date'=>$chronology_date ), + array( 'start' ) + ); + $res .= + '<a href="'.$url.'">' + .$this->get_date_component_label($i, $page['chronology_date'][$i]) + .'</a>'; + } + else + { + $res .= + '<span class="calInHere">' + .$this->get_date_component_label($i, $page['chronology_date'][$i]) + .'</span>'; + } + } + return $res; + } + +//--------------------------------------------------------- private members --- + /** + * Returns a display name for a date component optionally using labels + */ + function get_date_component_label($level, $date_component) + { + $label = $date_component; + if (isset($this->calendar_levels[$level]['labels'][$date_component])) + { + $label = $this->calendar_levels[$level]['labels'][$date_component]; + } + elseif ('any' === $date_component ) + { + $label = l10n('calendar_any'); + } + return $label; + } + + /** + * Gets a nice display name for a date to be shown in previos/next links. + */ + function get_date_nice_name($date) + { + $date_components = explode('-', $date); + $res = ''; + for ($i=count($date_components)-1; $i>=0; $i--) + { + if ('any' !== $date_components[$i]) + { + $label = $this->get_date_component_label($i, $date_components[$i] ); + if ( $res!='' ) + { + $res .= ' '; + } + $res .= $label; + } + } + return $res; + } + + /** + * Creates a calendar navigation bar. + * + * @param array date_components + * @param array items - hash of items to put in the bar (e.g. 2005,2006) + * @param string class_prefix - html class attribute prefix for span elements + * @param bool show_any - adds any link to the end of the bar + * @param bool show_empty - shows all labels even those without items + * @param array labels - optional labels for items (e.g. Jan,Feb,...) + * @return string the navigation bar + */ + function get_nav_bar_from_items($date_components, $items, + $class_prefix, $show_any, + $show_empty=false, $labels=null) + { + global $conf, $page; + + $nav_bar = ''; + + if ($conf['calendar_show_empty'] and $show_empty and !empty($labels) ) + { + foreach ($labels as $item => $label) + { + if ( ! isset($items[$item]) ) + { + $items[$item] = -1; + } + } + ksort($items); + } + + foreach ($items as $item => $nb_images) + { + $label = $item; + if (isset($labels[$item])) + { + $label = $labels[$item]; + } + if ($nb_images==-1) + { + $nav_bar .= '<span class="'.$class_prefix.'Empty">'; + $nav_bar .= $label; + } + else + { + $nav_bar .= '<span class="'.$class_prefix.'">'; + $url = duplicate_index_url( + array('chronology_date'=>array_merge($date_components,array($item))), + array( 'start' ) + ); + $nav_bar .= '<a href="'.$url.'">'; + $nav_bar .= $label; + $nav_bar .= '</a>'; + } + if ($nb_images > 0) + { + $nav_bar .= '('.$nb_images.')'; + } + $nav_bar.= '</span>'; + } + + if ($conf['calendar_show_any'] and $show_any and count($items)>1 and + count($date_components)<count($this->calendar_levels)-1 ) + { + $label = l10n('calendar_any'); + $nav_bar .= '<span class="'.$class_prefix.'">'; + $url = duplicate_index_url( + array('chronology_date'=>array_merge($date_components,array('any'))), + array( 'start' ) + ); + $nav_bar .= '<a href="'.$url.'">'; + $nav_bar .= $label; + $nav_bar .= '</a>'; + $nav_bar.= '</span>'; + } + return $nav_bar; + } + + /** + * Creates a calendar navigation bar for a given level. + * + * @param int level - the level (0-year,1-month/week,2-day) + * @return void + */ + function build_nav_bar($level, $labels=null) + { + global $template, $conf, $page; + + $query = ' +SELECT DISTINCT('.$this->calendar_levels[$level]['sql'] + .') as period'; + $query.= $this->inner_sql; + $query.= $this->get_date_where($level); + $query.= ' + GROUP BY period +;'; + + $level_items = array(); + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $level_items[$row['period']] = 0; + } + + if ( count($level_items)==1 and + count($page['chronology_date'])<count($this->calendar_levels)-1) + { + if ( ! isset($page['chronology_date'][$level]) ) + { + list($key) = array_keys($level_items); + $page['chronology_date'][$level] = (int)$key; + + if ( $level<count($page['chronology_date']) and + $level!=count($this->calendar_levels)-1 ) + { + return; + } + } + } + + $dates = $page['chronology_date']; + while ($level<count($dates)) + { + array_pop($dates); + } + + $nav_bar = $this->get_nav_bar_from_items( + $dates, + $level_items, + 'calItem', + true, + true, + isset($labels) ? $labels : $this->calendar_levels[$level]['labels'] + ); + + $template->append( + 'chronology_navigation_bars', + array( + 'CONTENT' => $nav_bar, + ) + ); + } + + /** + * Assigns the next/previous link to the template with regards to + * the currently choosen date. + */ + function build_next_prev() + { + global $template, $page; + $prev = $next =null; + if ( empty($page['chronology_date']) ) + return; + $query = 'SELECT CONCAT_WS("-"'; + for ($i=0; $i<count($page['chronology_date']); $i++) + { + if ( 'any' === $page['chronology_date'][$i] ) + { + $query .= ','.'"any"'; + } + else + { + $query .= ','.$this->calendar_levels[$i]['sql']; + } + } + $current = implode('-', $page['chronology_date'] ); + + $query.=') as period' . $this->inner_sql .' +AND ' . $this->date_field . ' IS NOT NULL +GROUP BY period'; + + $upper_items = array_from_query( $query, 'period'); + + usort($upper_items, 'version_compare'); + $upper_items_rank = array_flip($upper_items); + if ( !isset($upper_items_rank[$current]) ) + { + array_push($upper_items, $current);// just in case (external link) + usort($upper_items, 'version_compare'); + $upper_items_rank = array_flip($upper_items); + } + $current_rank = $upper_items_rank[$current]; + + $tpl_var = array(); + + if ( $current_rank>0 ) + { // has previous + $prev = $upper_items[$current_rank-1]; + $chronology_date = explode('-', $prev); + $tpl_var['previous'] = + array( + 'LABEL' => $this->get_date_nice_name($prev), + 'URL' => duplicate_index_url( + array('chronology_date'=>$chronology_date), array('start') + ) + ); + } + + if ( $current_rank < count($upper_items)-1 ) + { // has next + $next = $upper_items[$current_rank+1]; + $chronology_date = explode('-', $next); + $tpl_var['next'] = + array( + 'LABEL' => $this->get_date_nice_name($next), + 'URL' => duplicate_index_url( + array('chronology_date'=>$chronology_date), array('start') + ) + ); + } + + if ( !empty($tpl_var) ) + { + $existing = & $template->get_template_vars('chronology_navigation_bars'); + if ( !empty($existing) ) + { + $existing[ sizeof($existing)-1 ] = + array_merge( $existing[ sizeof($existing)-1 ], $tpl_var); + } + else + { + $template->append( 'chronology_navigation_bars', $tpl_var ); + } + } + } +} +?> diff --git a/BSF/include/calendar_monthly.class.php b/BSF/include/calendar_monthly.class.php new file mode 100644 index 000000000..b29997cef --- /dev/null +++ b/BSF/include/calendar_monthly.class.php @@ -0,0 +1,515 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +include_once(PHPWG_ROOT_PATH.'include/calendar_base.class.php'); + +define ('CYEAR', 0); +define ('CMONTH', 1); +define ('CDAY', 2); + +/** + * Monthly calendar style (composed of years/months and days) + */ +class Calendar extends CalendarBase +{ + + /** + * Initialize the calendar + * @param string inner_sql used for queries (INNER JOIN or normal) + */ + function initialize($inner_sql) + { + parent::initialize($inner_sql); + global $lang; + $this->calendar_levels = array( + array( + 'sql'=> 'YEAR('.$this->date_field.')', + 'labels' => null + ), + array( + 'sql'=> 'MONTH('.$this->date_field.')', + 'labels' => $lang['month'] + ), + array( + 'sql'=> 'DAYOFMONTH('.$this->date_field.')', + 'labels' => null + ), + ); + } + +/** + * Generate navigation bars for category page + * @return boolean false to indicate that thumbnails + * where not included here, true otherwise + */ +function generate_category_content() +{ + global $conf, $page; + + $view_type = $page['chronology_view']; + if ($view_type==CAL_VIEW_CALENDAR) + { + global $template; + $tpl_var = array(); + if ( count($page['chronology_date'])==0 ) + {//case A: no year given - display all years+months + if ($this->build_global_calendar($tpl_var)) + { + $template->assign('chronology_calendar', $tpl_var); + return true; + } + } + + if ( count($page['chronology_date'])==1 ) + {//case B: year given - display all days in given year + if ($this->build_year_calendar($tpl_var)) + { + $template->assign('chronology_calendar', $tpl_var); + $this->build_nav_bar(CYEAR); // years + return true; + } + } + + if ( count($page['chronology_date'])==2 ) + {//case C: year+month given - display a nice month calendar + if ( $this->build_month_calendar($tpl_var) ) + { + $template->assign('chronology_calendar', $tpl_var); + } + $this->build_next_prev(); + return true; + } + } + + if ($view_type==CAL_VIEW_LIST or count($page['chronology_date'])==3) + { + if ( count($page['chronology_date'])==0 ) + { + $this->build_nav_bar(CYEAR); // years + } + if ( count($page['chronology_date'])==1) + { + $this->build_nav_bar(CMONTH); // month + } + if ( count($page['chronology_date'])==2 ) + { + $day_labels = range( 1, $this->get_all_days_in_month( + $page['chronology_date'][CYEAR] ,$page['chronology_date'][CMONTH] ) ); + array_unshift($day_labels, 0); + unset( $day_labels[0] ); + $this->build_nav_bar( CDAY, $day_labels ); // days + } + $this->build_next_prev(); + } + return false; +} + + +/** + * Returns a sql where subquery for the date field + * @param int max_levels return the where up to this level + * (e.g. 2=only year and month) + * @return string + */ +function get_date_where($max_levels=3) +{ + global $page; + $date = $page['chronology_date']; + while (count($date)>$max_levels) + { + array_pop($date); + } + $res = ''; + if (isset($date[CYEAR]) and $date[CYEAR]!=='any') + { + $b = $date[CYEAR] . '-'; + $e = $date[CYEAR] . '-'; + if (isset($date[CMONTH]) and $date[CMONTH]!=='any') + { + $b .= $date[CMONTH] . '-'; + $e .= $date[CMONTH] . '-'; + if (isset($date[CDAY]) and $date[CDAY]!=='any') + { + $b .= $date[CDAY]; + $e .= $date[CDAY]; + } + else + { + $b .= '01'; + $e .= '31'; + } + } + else + { + $b .= '01-01'; + $e .= '12-31'; + if (isset($date[CMONTH]) and $date[CMONTH]!=='any') + { + $res .= ' AND '.$this->calendar_levels[CMONTH]['sql'].'='.$date[CMONTH]; + } + if (isset($date[CDAY]) and $date[CDAY]!=='any') + { + $res .= ' AND '.$this->calendar_levels[CDAY]['sql'].'='.$date[CDAY]; + } + } + $res = " AND $this->date_field BETWEEN '$b' AND '$e 23:59:59'" . $res; + } + else + { + $res = ' AND '.$this->date_field.' IS NOT NULL'; + if (isset($date[CMONTH]) and $date[CMONTH]!=='any') + { + $res .= ' AND '.$this->calendar_levels[CMONTH]['sql'].'='.$date[CMONTH]; + } + if (isset($date[CDAY]) and $date[CDAY]!=='any') + { + $res .= ' AND '.$this->calendar_levels[CDAY]['sql'].'='.$date[CDAY]; + } + } + return $res; +} + + + +//--------------------------------------------------------- private members --- + +// returns an array with alll the days in a given month +function get_all_days_in_month($year, $month) +{ + $md= array(1=>31,28,31,30,31,30,31,31,30,31,30,31); + + if ( is_numeric($year) and $month==2) + { + $nb_days = $md[2]; + if ( ($year%4==0) and ( ($year%100!=0) or ($year%400!=0) ) ) + { + $nb_days++; + } + } + elseif ( is_numeric($month) ) + { + $nb_days = $md[ $month ]; + } + else + { + $nb_days = 31; + } + return $nb_days; +} + +function build_global_calendar(&$tpl_var) +{ + global $page; + assert( count($page['chronology_date']) == 0 ); + $query='SELECT DISTINCT(DATE_FORMAT('.$this->date_field.',"%Y%m")) as period, + COUNT( DISTINCT(id) ) as count'; + $query.= $this->inner_sql; + $query.= $this->get_date_where(); + $query.= ' + GROUP BY period + ORDER BY YEAR('.$this->date_field.') DESC, MONTH('.$this->date_field.')'; + + $result = pwg_query($query); + $items=array(); + while ($row = mysql_fetch_array($result)) + { + $y = substr($row['period'], 0, 4); + $m = (int)substr($row['period'], 4, 2); + if ( ! isset($items[$y]) ) + { + $items[$y] = array('nb_images'=>0, 'children'=>array() ); + } + $items[$y]['children'][$m] = $row['count']; + $items[$y]['nb_images'] += $row['count']; + } + //echo ('<pre>'. var_export($items, true) . '</pre>'); + if (count($items)==1) + {// only one year exists so bail out to year view + list($y) = array_keys($items); + $page['chronology_date'][CYEAR] = $y; + return false; + } + + global $lang; + foreach ( $items as $year=>$year_data) + { + $chronology_date = array( $year ); + $url = duplicate_index_url( array('chronology_date'=>$chronology_date) ); + + $nav_bar = $this->get_nav_bar_from_items( $chronology_date, + $year_data['children'], 'calCal', false, false, $lang['month'] ); + + $tpl_var['calendar_bars'][] = + array( + 'U_HEAD' => $url, + 'NB_IMAGES' => $year_data['nb_images'], + 'HEAD_LABEL' => $year, + 'NAV_BAR' => $nav_bar, + ); + } + return true; +} + +function build_year_calendar(&$tpl_var) +{ + global $page; + assert( count($page['chronology_date']) == 1 ); + $query='SELECT DISTINCT(DATE_FORMAT('.$this->date_field.',"%m%d")) as period, + COUNT( DISTINCT(id) ) as count'; + $query.= $this->inner_sql; + $query.= $this->get_date_where(); + $query.= ' + GROUP BY period'; + + $result = pwg_query($query); + $items=array(); + while ($row = mysql_fetch_array($result)) + { + $m = (int)substr($row['period'], 0, 2); + $d = substr($row['period'], 2, 2); + if ( ! isset($items[$m]) ) + { + $items[$m] = array('nb_images'=>0, 'children'=>array() ); + } + $items[$m]['children'][$d] = $row['count']; + $items[$m]['nb_images'] += $row['count']; + } + if (count($items)==1) + { // only one month exists so bail out to month view + list($m) = array_keys($items); + $page['chronology_date'][CMONTH] = $m; + return false; + } + global $lang; + foreach ( $items as $month=>$month_data) + { + $chronology_date = array( $page['chronology_date'][CYEAR], $month ); + $url = duplicate_index_url( array('chronology_date'=>$chronology_date) ); + + $nav_bar = $this->get_nav_bar_from_items( $chronology_date, + $month_data['children'], 'calCal', false ); + + $tpl_var['calendar_bars'][] = + array( + 'U_HEAD' => $url, + 'NB_IMAGES' => $month_data['nb_images'], + 'HEAD_LABEL' => $lang['month'][$month], + 'NAV_BAR' => $nav_bar, + ); + } + return true; + +} + +function build_month_calendar(&$tpl_var) +{ + global $page; + $query='SELECT DISTINCT(DAYOFMONTH('.$this->date_field.')) as period, + COUNT( DISTINCT(id) ) as count'; + $query.= $this->inner_sql; + $query.= $this->get_date_where(); + $query.= ' + GROUP BY period'; + + $items=array(); + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $d = (int)$row['period']; + $items[$d] = array('nb_images'=>$row['count']); + } + + foreach ( $items as $day=>$data) + { + $page['chronology_date'][CDAY]=$day; + $query = ' +SELECT id, file,tn_ext,path, width, height, DAYOFWEEK('.$this->date_field.')-1 as dow'; + $query.= $this->inner_sql; + $query.= $this->get_date_where(); + $query.= ' + ORDER BY RAND() + LIMIT 0,1'; + unset ( $page['chronology_date'][CDAY] ); + + $row = mysql_fetch_assoc(pwg_query($query)); + $items[$day]['tn_url'] = get_thumbnail_url($row); + $items[$day]['file'] = $row['file']; + $items[$day]['path'] = $row['path']; + $items[$day]['tn_ext'] = @$row['tn_ext']; + $items[$day]['width'] = $row['width']; + $items[$day]['height'] = $row['height']; + $items[$day]['dow'] = $row['dow']; + } + + global $lang, $conf; + + if ( !empty($items) + and $conf['calendar_month_cell_width']>0 + and $conf['calendar_month_cell_height']>0) + { + list($known_day) = array_keys($items); + $known_dow = $items[$known_day]['dow']; + $first_day_dow = ($known_dow-($known_day-1))%7; + if ($first_day_dow<0) + { + $first_day_dow += 7; + } + //first_day_dow = week day corresponding to the first day of this month + $wday_labels = $lang['day']; + + // BEGIN - pass now in week starting Monday + if ($first_day_dow==0) + { + $first_day_dow = 6; + } + else + { + $first_day_dow -= 1; + } + array_push( $wday_labels, array_shift($wday_labels) ); + // END - pass now in week starting Monday + + $cell_width = $conf['calendar_month_cell_width']; + $cell_height = $conf['calendar_month_cell_height']; + + $tpl_weeks = array(); + $tpl_crt_week = array(); + + //fill the empty days in the week before first day of this month + for ($i=0; $i<$first_day_dow; $i++) + { + $tpl_crt_week[] = array(); + } + + for ( $day = 1; + $day <= $this->get_all_days_in_month( + $page['chronology_date'][CYEAR], $page['chronology_date'][CMONTH] + ); + $day++) + { + $dow = ($first_day_dow + $day-1)%7; + if ($dow==0 and $day!=1) + { + $tpl_weeks[] = $tpl_crt_week; // add finished week to week list + $tpl_crt_week = array(); // start new week + } + + if ( !isset($items[$day]) ) + {// empty day + $tpl_crt_week[] = + array( + 'DAY' => $day + ); + } + else + { + $thumb = get_thumbnail_path($items[$day]); + $tn_size = @getimagesize($thumb); + + $tn_width = $tn_size[0]; + $tn_height = $tn_size[1]; + + // now need to fit the thumbnail of size tn_size within + // a cell of size cell_size by playing with CSS position (left/top) + // and the width and height of <img>. + $ratio_w = $tn_width/$cell_width; + $ratio_h = $tn_height/$cell_height; + + $pos_top=$pos_left=0; + $css_style = ''; + + if ( $ratio_w>1 and $ratio_h>1) + {// cell completely smaller than the thumbnail so we will let the browser + // resize the thumbnail + if ($ratio_w > $ratio_h ) + {// thumbnail ratio compared to cell -> wide format + $css_style = 'height:'.$cell_height.'px;'; + $browser_img_width = $cell_height*$tn_width/$tn_height; + $pos_left = ($browser_img_width-$cell_width)/2; + } + else + { + $css_style = 'width:'.$cell_width.'px;'; + $browser_img_height = $cell_width*$tn_height/$tn_width; + $pos_top = ($browser_img_height-$cell_height)/2; + } + } + else + { + $pos_left = ($tn_width-$cell_width)/2; + $pos_top = ($tn_height-$cell_height)/2; + } + + if ( round($pos_left)!=0) + { + $css_style.='left:'.round(-$pos_left).'px;'; + } + if ( round($pos_top)!=0) + { + $css_style.='top:'.round(-$pos_top).'px;'; + } + $url = duplicate_index_url( + array( + 'chronology_date' => + array( + $page['chronology_date'][CYEAR], + $page['chronology_date'][CMONTH], + $day + ) + ) + ); + + $tpl_crt_week[] = + array( + 'DAY' => $day, + 'DOW' => $dow, + 'NB_ELEMENTS' => $items[$day]['nb_images'], + 'IMAGE' => $items[$day]['tn_url'], + 'U_IMG_LINK' => $url, + 'IMAGE_STYLE' => $css_style, + 'IMAGE_ALT' => $items[$day]['file'], + ); + } + } + //fill the empty days in the week after the last day of this month + while ( $dow<6 ) + { + $tpl_crt_week[] = array(); + $dow++; + } + $tpl_weeks[] = $tpl_crt_week; + + $tpl_var['month_view'] = + array( + 'CELL_WIDTH' => $cell_width, + 'CELL_HEIGHT' => $cell_height, + 'wday_labels' => $wday_labels, + 'weeks' => $tpl_weeks, + ); + } + + return true; +} + +} +?> diff --git a/BSF/include/calendar_weekly.class.php b/BSF/include/calendar_weekly.class.php new file mode 100644 index 000000000..2077bc594 --- /dev/null +++ b/BSF/include/calendar_weekly.class.php @@ -0,0 +1,136 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +include_once(PHPWG_ROOT_PATH.'include/calendar_base.class.php'); + +define ('CYEAR', 0); +define ('CWEEK', 1); +define ('CDAY', 2); + +/** + * Weekly calendar style (composed of years/week in years and days in week) + */ +class Calendar extends CalendarBase +{ + + /** + * Initialize the calendar + * @param string inner_sql used for queries (INNER JOIN or normal) + */ + function initialize($inner_sql) + { + parent::initialize($inner_sql); + global $lang; + $week_no_labels=array(); + for ($i=1; $i<=53; $i++) + { + $week_no_labels[$i] = sprintf( l10n("Week %d"), $i); + //$week_no_labels[$i] = $i; + } + + $this->calendar_levels = array( + array( + 'sql'=> 'YEAR('.$this->date_field.')', + 'labels' => null + ), + array( + 'sql'=> 'WEEK('.$this->date_field.')+1', + 'labels' => $week_no_labels, + ), + array( + 'sql'=> 'DAYOFWEEK('.$this->date_field.')-1', + 'labels' => $lang['day'] + ), + ); + //Comment next lines for week starting on Sunday or if MySQL version<4.0.17 + //WEEK(date,5) = "0-53 - Week 1=the first week with a Monday in this year" + $this->calendar_levels[CWEEK]['sql'] = 'WEEK('.$this->date_field.',5)+1'; + $this->calendar_levels[CDAY]['sql'] = 'WEEKDAY('.$this->date_field.')'; + array_push( $this->calendar_levels[CDAY]['labels'], + array_shift( $this->calendar_levels[CDAY]['labels'] ) ); + } + +/** + * Generate navigation bars for category page + * @return boolean false to indicate that thumbnails where not included here + */ +function generate_category_content() +{ + global $conf, $page; + + if ( count($page['chronology_date'])==0 ) + { + $this->build_nav_bar(CYEAR); // years + } + if ( count($page['chronology_date'])==1 ) + { + $this->build_nav_bar(CWEEK, array()); // week nav bar 1-53 + } + if ( count($page['chronology_date'])==2 ) + { + $this->build_nav_bar(CDAY); // days nav bar Mon-Sun + } + $this->build_next_prev(); + return false; +} + + +/** + * Returns a sql where subquery for the date field + * @param int max_levels return the where up to this level + * (e.g. 2=only year and week in year) + * @return string + */ +function get_date_where($max_levels=3) +{ + global $page; + $date = $page['chronology_date']; + while (count($date)>$max_levels) + { + array_pop($date); + } + $res = ''; + if (isset($date[CYEAR]) and $date[CYEAR]!=='any') + { + $y = $date[CYEAR]; + $res = " AND $this->date_field BETWEEN '$y-01-01' AND '$y-12-31 23:59:59'"; + } + + if (isset($date[CWEEK]) and $date[CWEEK]!=='any') + { + $res .= ' AND '.$this->calendar_levels[CWEEK]['sql'].'='.$date[CWEEK]; + } + if (isset($date[CDAY]) and $date[CDAY]!=='any') + { + $res .= ' AND '.$this->calendar_levels[CDAY]['sql'].'='.$date[CDAY]; + } + if (empty($res)) + { + $res = ' AND '.$this->date_field.' IS NOT NULL'; + } + return $res; +} + +} + +?> diff --git a/BSF/include/category_cats.inc.php b/BSF/include/category_cats.inc.php new file mode 100644 index 000000000..e7f9a168a --- /dev/null +++ b/BSF/include/category_cats.inc.php @@ -0,0 +1,298 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * This file is included by the main page to show thumbnails for a category + * that have only subcategories or to show recent categories + * + */ + +if ($page['section']=='recent_cats') +{ + // $user['forbidden_categories'] including with USER_CACHE_CATEGORIES_TABLE + $query = ' +SELECT + id, name, permalink, representative_picture_id, comment, nb_images, uppercats, + date_last, max_date_last, count_images, count_categories, global_rank + FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' + ON id = cat_id and user_id = '.$user['id'].' + WHERE date_last >= SUBDATE( + CURRENT_DATE,INTERVAL '.$user['recent_period'].' DAY + ) +'.get_sql_condition_FandF + ( + array + ( + 'visible_categories' => 'id', + ), + 'AND' + ).' +;'; +} +else +{ + // $user['forbidden_categories'] including with USER_CACHE_CATEGORIES_TABLE + $query = ' +SELECT + id, name, permalink, representative_picture_id, comment, nb_images, uppercats, + date_last, max_date_last, count_images, count_categories + FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' + ON id = cat_id and user_id = '.$user['id'].' + WHERE id_uppercat '. + (!isset($page['category']) ? 'is NULL' : '= '.$page['category']['id']).' +'.get_sql_condition_FandF + ( + array + ( + 'visible_categories' => 'id', + ), + 'AND' + ).' + ORDER BY rank +;'; +} + +$result = pwg_query($query); +$categories = array(); +$category_ids = array(); +$image_ids = array(); + +while ($row = mysql_fetch_assoc($result)) +{ + $row['is_child_date_last'] = @$row['max_date_last']>@$row['date_last']; + + if (isset($row['representative_picture_id']) + and is_numeric($row['representative_picture_id'])) + { // if a representative picture is set, it has priority + $image_id = $row['representative_picture_id']; + } + else if ($conf['allow_random_representative']) + {// searching a random representant among elements in sub-categories + $query = ' +SELECT image_id + FROM '.CATEGORIES_TABLE.' AS c INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic + ON ic.category_id = c.id'; + $query.= ' + WHERE (c.id='.$row['id'].' OR uppercats LIKE \''.$row['uppercats'].',%\')' + .get_sql_condition_FandF + ( + array + ( + 'forbidden_categories' => 'c.id', + 'visible_categories' => 'c.id', + 'visible_images' => 'image_id' + ), + "\n AND" + ).' + ORDER BY RAND() + LIMIT 0,1 +;'; + $subresult = pwg_query($query); + if (mysql_num_rows($subresult) > 0) + { + list($image_id) = mysql_fetch_row($subresult); + } + } + else + { // searching a random representant among representant of sub-categories + $query = ' +SELECT representative_picture_id + FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' + ON id = cat_id and user_id = '.$user['id'].' + WHERE uppercats LIKE \''.$row['uppercats'].',%\' + AND representative_picture_id IS NOT NULL' + .get_sql_condition_FandF + ( + array + ( + 'visible_categories' => 'id', + ), + "\n AND" + ).' + ORDER BY RAND() + LIMIT 0,1 +;'; + $subresult = pwg_query($query); + if (mysql_num_rows($subresult) > 0) + { + list($image_id) = mysql_fetch_row($subresult); + } + } + + if (isset($image_id)) + { + $row['representative_picture_id'] = $image_id; + array_push($image_ids, $image_id); + array_push($categories, $row); + array_push($category_ids, $row['id']); + } + unset($image_id); +} + +if ($conf['display_fromto']) +{ + $dates_of_category = array(); + if (count($category_ids) > 0) + { + $query = ' +SELECT + category_id, + MIN(date_creation) AS date_creation_min, + MAX(date_creation) AS date_creation_max + FROM '.IMAGE_CATEGORY_TABLE.' + INNER JOIN '.IMAGES_TABLE.' ON image_id = id + WHERE category_id IN ('.implode(',', $category_ids).') +'.get_sql_condition_FandF + ( + array + ( + 'visible_categories' => 'category_id', + 'visible_images' => 'id' + ), + 'AND' + ).' + GROUP BY category_id +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $dates_of_category[ $row['category_id'] ] = array( + 'from' => $row['date_creation_min'], + 'to' => $row['date_creation_max'], + ); + } + } +} + +if ($page['section']=='recent_cats') +{ + usort($categories, 'global_rank_compare'); +} +if (count($categories) > 0) +{ + $thumbnail_src_of = array(); + + $query = ' +SELECT id, path, tn_ext + FROM '.IMAGES_TABLE.' + WHERE id IN ('.implode(',', $image_ids).') +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $thumbnail_src_of[$row['id']] = get_thumbnail_url($row); + } +} + +if (count($categories) > 0) +{ + // Update filtered data + if (function_exists('update_cats_with_filtered_data')) + { + update_cats_with_filtered_data($categories); + } + + $template->set_filename('index_category_thumbnails', 'mainpage_categories.tpl'); + + trigger_action('loc_begin_index_category_thumbnails', $categories); + + foreach ($categories as $category) + { + if ($page['section']=='recent_cats') + { + $name = get_cat_display_name_cache($category['uppercats'], null, false); + } + else + { + $name = $category['name']; + } + + $icon_ts = get_icon($category['max_date_last'], $category['is_child_date_last']); + + $tpl_var = + array( + 'ID' => $category['id'], + 'TN_SRC' => $thumbnail_src_of[$category['representative_picture_id']], + 'ALT' => $category['name'], + 'ICON' => $icon_ts, + + 'URL' => make_index_url( + array( + 'category' => $category + ) + ), + 'CAPTION_NB_IMAGES' => get_display_images_count + ( + $category['nb_images'], + $category['count_images'], + $category['count_categories'], + true, + '<br />' + ), + 'DESCRIPTION' => + trigger_event('render_category_literal_description', + trigger_event('render_category_description', + @$category['comment'], + 'subcatify_category_description')), + 'NAME' => $name, + ); + + if ($conf['display_fromto']) + { + if (isset($dates_of_category[ $category['id'] ])) + { + $from = $dates_of_category[ $category['id'] ]['from']; + $to = $dates_of_category[ $category['id'] ]['to']; + + if (!empty($from)) + { + $info = ''; + + if ($from == $to) + { + $info = format_date($from); + } + else + { + $info = sprintf( + l10n('from %s to %s'), + format_date($from), + format_date($to) + ); + } + $tpl_var['INFO_DATES'] = $info; + } + } + }//fromto + + //plugins need to add/modify sth in this loop ? + $tpl_var = trigger_event('loc_index_category_thumbnail', + $tpl_var, $category ); + + $template->append( 'category_thumbnails', $tpl_var); + } + + trigger_action('loc_end_index_category_thumbnails', $categories); + $template->assign_var_from_handle('CATEGORIES', 'index_category_thumbnails'); +} +?> diff --git a/BSF/include/category_default.inc.php b/BSF/include/category_default.inc.php new file mode 100644 index 000000000..8dad04d90 --- /dev/null +++ b/BSF/include/category_default.inc.php @@ -0,0 +1,170 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * This file is included by the main page to show thumbnails for the default + * case + * + */ + +$page['rank_of'] = array_flip($page['items']); + +$pictures = array(); + +$selection = array_slice( + $page['items'], + $page['start'], + $page['nb_image_page'] + ); + +if (count($selection) > 0) +{ + $query = ' +SELECT * + FROM '.IMAGES_TABLE.' + WHERE id IN ('.implode(',', $selection).') +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $row['rank'] = $page['rank_of'][ $row['id'] ]; + + array_push($pictures, $row); + } + + usort($pictures, 'rank_compare'); +} + +if (count($pictures) > 0) +{ + // define category slideshow url + $row = reset($pictures); + $page['cat_slideshow_url'] = + add_url_params( + duplicate_picture_url( + array( + 'image_id' => $row['id'], + 'image_file' => $row['file'] + ), + array('start') + ), + array('slideshow' => + (isset($_GET['slideshow']) ? $_GET['slideshow'] + : '' )) + ); + + if ($user['show_nb_comments']) + { + $query = ' +SELECT image_id, COUNT(*) AS nb_comments + FROM '.COMMENTS_TABLE.' + WHERE validated = \'true\' + AND image_id IN ('.implode(',', $selection).') + GROUP BY image_id +;'; + $nb_comments_of = simple_hash_from_query($query, 'image_id', 'nb_comments'); + } +} + +// template thumbnail initialization +$template->set_filenames( array( 'index_thumbnails' => 'thumbnails.tpl',)); + +trigger_action('loc_begin_index_thumbnails', $pictures); + +foreach ($pictures as $row) +{ + $thumbnail_url = get_thumbnail_url($row); + + // link on picture.php page + $url = duplicate_picture_url( + array( + 'image_id' => $row['id'], + 'image_file' => $row['file'] + ), + array('start') + ); + + $tpl_var = + array( + 'ID' => $row['id'], + 'IMAGE' => $thumbnail_url, + 'IMAGE_ALT' => $row['file'], + 'IMAGE_TITLE' => get_thumbnail_title($row), + 'IMAGE_TS' => get_icon($row['date_available']), + 'U_IMG_LINK' => $url, + ); + + if ($user['show_nb_hits']) + { + $tpl_var['NB_HITS'] = $row['hit']; + } + + if ($conf['show_thumbnail_caption']) + { + // name of the picture + if (isset($row['name']) and $row['name'] != '') + { + $name = $row['name']; + } + else + { + $name = str_replace('_', ' ', get_filename_wo_extension($row['file'])); + } + + switch ($page['section']) + { + case 'best_rated' : + { + $name = '('.$row['average_rate'].') '.$name; + break; + } + case 'most_visited' : + { + if ( !$user['show_nb_hits']) { + $name = '('.$row['hit'].') '.$name; + } + break; + } + } + + $tpl_var['ELEMENT_NAME'] = $name; + } + + if ( isset($nb_comments_of) ) + { + $row['nb_comments'] = isset($nb_comments_of[$row['id']]) + ? (int)$nb_comments_of[$row['id']] : 0; + $tpl_var['NB_COMMENTS'] = $row['nb_comments']; + } + + //plugins need to add/modify sth in this loop ? + $tpl_var = trigger_event('loc_index_thumbnail', $tpl_var, $row); + + $template->append('thumbnails', $tpl_var); +} + +trigger_action('loc_end_index_thumbnails', $pictures); +$template->assign_var_from_handle('THUMBNAILS', 'index_thumbnails'); + +pwg_debug('end include/category_default.inc.php'); +?> diff --git a/BSF/include/class_smtp_mail.inc.php b/BSF/include/class_smtp_mail.inc.php new file mode 100644 index 000000000..06ef69efd --- /dev/null +++ b/BSF/include/class_smtp_mail.inc.php @@ -0,0 +1,157 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// These function were originally a part of the punBB. + +class smtp_mail +{ + var $socket; + var $no_error; + var $host; + var $user; + var $password; + var $email_webmaster; + + function smtp_mail($host, $user, $password, $email_webmaster) + { + $this->host = $host; + $this->user = $user; + $this->password = $password; + $this->email_webmaster = $email_webmaster; + } + + // Adaptation of server_parse + function server_parse($expected_response) + { + if ($this->no_error) + { + $server_response = ''; + while (substr($server_response, 3, 1) != ' ') + { + if (!($server_response = fgets($this->socket, 256))) + { + trigger_error('Couldn\'t get mail server response codes.', E_USER_WARNING); + $this->no_error = false; + } + } + } + + if ($this->no_error) + { + if (!(substr($server_response, 0, 3) == $expected_response)) + { + trigger_error('Unable to send e-mail. Error message reported by the SMTP server: "'.$server_response.'"', E_USER_WARNING); + $this->no_error = false; + } + } + return $this->no_error; + } + + function server_write($s) + { + $this->no_error = $this->no_error && (fwrite($this->socket, $s) !== false); + return $this->no_error; + } + + // Adaptation of pun_mail + function mail($to, $subject, $message, $headers = '') + { + $this->no_error = true; + + $recipients = explode(',', $to); + + // Are we using port 25 or a custom port? + if (strpos($this->host, ':') !== false) + { + list($smtp_host, $smtp_port) = explode(':', $this->host); + } + else + { + $smtp_host = $this->host; + $smtp_port = 25; + } + + if ($this->socket = fsockopen($smtp_host, $smtp_port, $errno, $errstr, 15)) + { + $this->server_parse('220'); + + if (!empty($this->user) && !empty($this->password)) + { + $this->server_write('EHLO '.$smtp_host."\r\n"); + $this->server_parse('250'); + + $this->server_write('AUTH LOGIN'."\r\n"); + $this->server_parse('334'); + + $this->server_write(base64_encode($this->user)."\r\n"); + $this->no_error = $this->no_error && $this->no_error = $this->server_parse('334'); + + $this->server_write(base64_encode($this->password)."\r\n"); + $this->server_parse('235'); + } + else + { + $this->server_write('HELO '.$smtp_host."\r\n"); + $this->server_parse('250'); + } + + $this->server_write('MAIL FROM: <'.$this->email_webmaster.'>'."\r\n"); + $this->server_parse('250'); + + if (preg_match('/^\s*to\s*:.*/mi', $headers) === 0) + { + $to_header = 'To: '.implode(',', array_map(create_function('$email','return "<".$email.">";'), $recipients)); + } + else + { + $to_header = ''; + } + + @reset($recipients); + while (list(, $email) = @each($recipients)) + { + $this->server_write('RCPT TO: <'.$email.'>'."\r\n"); + $this->server_parse('250'); + } + + $this->server_write('DATA'."\r\n"); + $this->server_parse('354'); + + $this->server_write('Subject: '.$subject."\r\n".(empty($to_header) ? "" : $to_header."\r\n").$headers."\r\n\r\n".$message."\r\n"); + $this->server_write('.'."\r\n"); + $this->server_parse('250'); + + $this->server_write('QUIT'."\r\n"); + fclose($this->socket); + } + else + { + trigger_error('Could not connect to smtp host "'.$this->host.'" ('.$errno.') ('.$errstr.')', E_USER_WARNING); + $this->no_error = false;; + } + + return $this->no_error; + } +} + +?> diff --git a/BSF/include/common.inc.php b/BSF/include/common.inc.php new file mode 100644 index 000000000..45c6a3845 --- /dev/null +++ b/BSF/include/common.inc.php @@ -0,0 +1,283 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +if (!defined('PHPWG_ROOT_PATH')) +{ + die('Hacking attempt!'); +} +// determine the initial instant to indicate the generation time of this page +$t1 = explode( ' ', microtime() ); +$t2 = explode( '.', $t1[0] ); +$t2 = $t1[1].'.'.$t2[1]; + +set_magic_quotes_runtime(0); // Disable magic_quotes_runtime + +// +// addslashes to vars if magic_quotes_gpc is off this is a security +// precaution to prevent someone trying to break out of a SQL statement. +// +if( !get_magic_quotes_gpc() ) +{ + if( is_array( $_GET ) ) + { + while( list($k, $v) = each($_GET) ) + { + if( is_array($_GET[$k]) ) + { + while( list($k2, $v2) = each($_GET[$k]) ) + { + $_GET[$k][$k2] = addslashes($v2); + } + @reset($_GET[$k]); + } + else + { + $_GET[$k] = addslashes($v); + } + } + @reset($_GET); + } + + if( is_array($_POST) ) + { + while( list($k, $v) = each($_POST) ) + { + if( is_array($_POST[$k]) ) + { + while( list($k2, $v2) = each($_POST[$k]) ) + { + $_POST[$k][$k2] = addslashes($v2); + } + @reset($_POST[$k]); + } + else + { + $_POST[$k] = addslashes($v); + } + } + @reset($_POST); + } + + if( is_array($_COOKIE) ) + { + while( list($k, $v) = each($_COOKIE) ) + { + if( is_array($_COOKIE[$k]) ) + { + while( list($k2, $v2) = each($_COOKIE[$k]) ) + { + $_COOKIE[$k][$k2] = addslashes($v2); + } + @reset($_COOKIE[$k]); + } + else + { + $_COOKIE[$k] = addslashes($v); + } + } + @reset($_COOKIE); + } +} + +// +// Define some basic configuration arrays this also prevents malicious +// rewriting of language and otherarray values via URI params +// +$conf = array(); +$page = array(); +$user = array(); +$lang = array(); +$header_msgs = array(); +$header_notes = array(); +$filter = array(); + +@include(PHPWG_ROOT_PATH .'include/mysql.inc.php'); +if (!defined('PHPWG_INSTALLED')) +{ + header('Location: install.php'); + exit; +} + +foreach( array( + 'array_intersect_key', //PHP 5 >= 5.1.0RC1 + 'hash_hmac', //(hash) - enabled by default as of PHP 5.1.2 + 'preg_last_error', // PHP 5 >= 5.2.0 + 'file_put_contents', //PHP5 + ) as $func) +{ + if (!function_exists($func)) + { + include_once(PHPWG_ROOT_PATH . 'include/php_compat/'.$func.'.php'); + } +} + +include(PHPWG_ROOT_PATH . 'include/config_default.inc.php'); +@include(PHPWG_ROOT_PATH. 'include/config_local.inc.php'); +include(PHPWG_ROOT_PATH . 'include/constants.php'); +include(PHPWG_ROOT_PATH . 'include/functions.inc.php'); +include(PHPWG_ROOT_PATH . 'include/template.class.php'); + +// Database connection +mysql_connect( $cfgHote, $cfgUser, $cfgPassword ) +or die ( "Could not connect to database server" ); +mysql_select_db( $cfgBase ) +or die ( "Could not connect to database" ); + +defined('PWG_CHARSET') and defined('DB_CHARSET') + or die('PWG_CHARSET and/or DB_CHARSET is not defined'); +if ( version_compare(mysql_get_server_info(), '4.1.0', '>=') ) +{ + if (DB_CHARSET!='') + { + pwg_query('SET NAMES "'.DB_CHARSET.'"'); + } +} +else +{ + if ( strtolower(PWG_CHARSET)!='iso-8859-1' ) + { + die('PWG supports only iso-8859-1 charset on MySql version '.mysql_get_server_info()); + } +} + +// +// Setup gallery wide options, if this fails then we output a CRITICAL_ERROR +// since basic gallery information is not available +// +load_conf_from_db(); +load_plugins(); + +include(PHPWG_ROOT_PATH.'include/user.inc.php'); + + +// language files +load_language('common.lang'); +if (defined('IN_ADMIN') and IN_ADMIN) +{ + load_language('admin.lang'); +} +trigger_action('loading_lang'); +load_language('local.lang'); + +// only now we can set the localized username of the guest user (and not in +// include/user.inc.php) +if (is_a_guest()) +{ + $user['username'] = l10n('guest'); +} + +// template instance +if + ( + defined('IN_ADMIN') and IN_ADMIN and + isset($user['admin_template']) and + isset($user['admin_theme']) + ) +{ + // Admin template + $template = new Template(PHPWG_ROOT_PATH.'template/'.$user['admin_template'], $user['admin_theme'] ); +} +else +{ + // Classic template + $template = new Template(PHPWG_ROOT_PATH.'template/'.$user['template'], $user['theme'] ); +} + +if (isset($user['internal_status']['guest_must_be_guest']) + and + $user['internal_status']['guest_must_be_guest'] === true) +{ + $header_msgs[] = l10n('guest_must_be_guest'); +} + +if ($conf['gallery_locked']) +{ + $header_msgs[] = l10n('gallery_locked_message'); + + if ( script_basename() != 'identification' and !is_admin() ) + { + set_status_header(503, 'Service Unavailable'); + @header('Retry-After: 900'); + echo l10n('gallery_locked_message') + .'<a href="'.get_absolute_root_url(false).'identification.php">.</a>'; + exit(); + } +} + +if ($conf['check_upgrade_feed'] + and defined('PHPWG_IN_UPGRADE') + and PHPWG_IN_UPGRADE) +{ + + // retrieve already applied upgrades + $query = ' +SELECT id + FROM '.UPGRADE_TABLE.' +;'; + $applied = array_from_query($query, 'id'); + + // retrieve existing upgrades + $existing = get_available_upgrade_ids(); + + // which upgrades need to be applied? + if (count(array_diff($existing, $applied)) > 0) + { + $header_msgs[] = 'Some database upgrades are missing, ' + .'<a href="'.get_absolute_root_url(false).'upgrade_feed.php">upgrade now</a>'; + } +} + +if (is_adviser()) +{ + $header_msgs[] = l10n('adviser_mode_enabled'); +} + +if (count($header_msgs) > 0) +{ + $template->assign('header_msgs', $header_msgs); + $header_msgs=array(); +} + +if (!empty($conf['filter_pages']) and get_filter_page_value('used')) +{ + include(PHPWG_ROOT_PATH.'include/functions_filter.inc.php'); + include(PHPWG_ROOT_PATH.'include/filter.inc.php'); +} +else +{ + $filter['enabled'] = false; +} + +if (isset($conf['header_notes'])) +{ + $header_notes = array_merge($header_notes, $conf['header_notes']); +} + +// default event handlers +add_event_handler('render_category_literal_description', 'render_category_literal_description'); +add_event_handler('render_category_description', 'render_category_description'); +add_event_handler('render_comment_content', 'htmlspecialchars'); +add_event_handler('render_comment_content', 'parse_comment_content'); +add_event_handler('render_comment_author', 'strip_tags'); +trigger_action('init'); +?> diff --git a/BSF/include/config_default.inc.php b/BSF/include/config_default.inc.php new file mode 100644 index 000000000..cb78729ef --- /dev/null +++ b/BSF/include/config_default.inc.php @@ -0,0 +1,700 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * configuration page + * + * Set configuration parameters that are not in the table config. In the + * application, configuration parameters are considered in the same way + * coming from config table or config_default.inc.php. + * + * It is recommended to let config_default.inc.php as provided and to + * overwrite configuration in your local configuration file + * config_local.inc.php. See tools/config_local.inc.php as an example. + * + * Why having some parameters in config table and others in + * config_*.inc.php? Modifying config_*.inc.php is a "hard" task for low + * skilled users, they need a GUI for this : admin/configuration. But only + * parameters that might be modified by low skilled users are in config + * table, other parameters are in config_*.inc.php + */ + +// +-----------------------------------------------------------------------+ +// | misc | +// +-----------------------------------------------------------------------+ + +// order_by : how to change the order of display for images in a category ? +// +// There are several fields that can order the display : +// +// - date_available : the date of the adding to the gallery +// - file : the name of the file +// - id : element identifier +// - date_creation : date of element creation +// +// Once you've chosen which field(s) to use for ordering, you must chose the +// ascending or descending order for each field. examples : +// +// 1. $conf['order_by'] = " order by date_available desc, file asc"; +// will order pictures by date_available descending & by filename ascending +// +// 2. $conf['order_by'] = " order by file asc"; +// will only order pictures by file ascending without taking into account +// the date_available +$conf['order_by'] = ' ORDER BY date_available DESC, file ASC, id ASC'; + +// file_ext : file extensions (case sensitive) authorized +$conf['file_ext'] = array('jpg','JPG','jpeg','JPEG', + 'png','PNG','gif','GIF','mpg','zip', + 'avi','mp3','ogg'); + +// picture_ext : file extensions for picture file, must be a subset of +// file_ext +$conf['picture_ext'] = array('jpg','JPG','jpeg','JPEG', + 'png','PNG','gif','GIF'); + +// top_number : number of element to display for "best rated" and "most +// visited" categories +$conf['top_number'] = 15; + +// anti-flood_time : number of seconds between 2 comments : 0 to disable +$conf['anti-flood_time'] = 60; + +// qualified spam comments are not registered (false will register them +// but they will require admin validation) +$conf['comment_spam_reject'] = true; + +// maximum number of links in a comment before it is qualified spam +$conf['comment_spam_max_links'] = 3; + +// calendar_datefield : date field of table "images" used for calendar +// catgory +$conf['calendar_datefield'] = 'date_creation'; + +// calendar_show_any : the calendar shows an aditional 'any' button in the +// year/month/week/day navigation bars +$conf['calendar_show_any'] = true; + +// calendar_show_empty : the calendar shows month/weeks/days even if there are +//no elements for these +$conf['calendar_show_empty'] = true; + +// calendar_month_cell_width, calendar_month_cell_height : define the +// width and the height of a cell in the monthly calendar when viewing a +// given month. a value of 0 means that the pretty view is not shown. +// a good suggestion would be to have the width and the height equal +// and smaller than tn_width and tn_height. +$conf['calendar_month_cell_width'] =80; +$conf['calendar_month_cell_height']=80; + +// newcat_default_commentable : at creation, must a category be commentable +// or not ? +$conf['newcat_default_commentable'] = true; + +// newcat_default_uploadable : at creation, must a category be uploadable or +// not ? +$conf['newcat_default_uploadable'] = false; + +// newcat_default_visible : at creation, must a category be visible or not ? +// Warning : if the parent category is invisible, the category is +// automatically create invisible. (invisible = locked) +$conf['newcat_default_visible'] = true; + +// newcat_default_status : at creation, must a category be public or private +// ? Warning : if the parent category is private, the category is +// automatically create private. +$conf['newcat_default_status'] = 'public'; + +// level_separator : character string used for separating a category level +// to the sub level. Suggestions : ' / ', ' » ', ' → ', ' - ', +// ' >' +$conf['level_separator'] = ' / '; + +// paginate_pages_around : on paginate navigation bar, how many pages +// display before and after the current page ? +$conf['paginate_pages_around'] = 2; + +// tn_width : default width for thumbnails creation +$conf['tn_width'] = 128; + +// tn_height : default height for thumbnails creation +$conf['tn_height'] = 128; + +// show_version : shall the version of Piwigo be displayed at the +// bottom of each page ? +$conf['show_version'] = true; + + +// links : list of external links to add in the menu. An example is the best +// than a long explanation : +// +// Simple use: +// for each link is associated a label +// $conf['links'] = array( +// 'http://piwigo.org' => 'PWG website', +// 'http://forum.phpwebgallery.net' => 'PWG forum', +// 'http://phpwebgallery.net/doc' => 'PWG wiki' +// ); +// +// Advenced use: +// You can also used special options. Instead to pass a string like parameter value +// you can pass a array with different optional parameter values +// $conf['links'] = array( +// 'http://piwigo.org' => array('label' => 'PWG website', 'new_window' => false, 'eval_visible' => 'return true;'), +// 'http://forum.phpwebgallery.net' => array('label' => 'For ADMIN', 'new_window' => true, 'eval_visible' => 'return is_admin();'), +// 'http://phpwebgallery.net/doc' => array('label' => 'For Guest', 'new_window' => true, 'eval_visible' => 'return is_a_guest();'), +// 'http://download.gna.org/phpwebgallery/' => +// array('label' => 'PopUp', 'new_window' => true, +// 'nw_name' => 'PopUp', 'nw_features' => 'width=800,height=450,location=no,status=no,toolbar=no,scrollbars=no,menubar=no'), +// ); +// Parameters: +// 'label': +// Label to display for the link, must be defined +// 'new_window': +// If true open link on tab/window +// [Default value is true if it's not defined] +// 'nw_name': +// Name use when new_window is true +// [Default value is '' if it's not defined] +// 'nw_features': +// features use when new_window is true +// [Default value is '' if it's not defined] +// 'eval_visible': +// It's php code witch must return if the link is visible or not +// [Default value is true if it's not defined] +// +// Equivalence: +// $conf['links'] = array( +// 'http://piwigo.org' => 'PWG website', +// ); +// $conf['links'] = array( +// 'http://piwigo.org' => array('label' => 'PWG website', 'new_window' => false, 'visible' => 'return true;'), +// ); +// +// If the array is empty, the "Links" box won't be displayed on the main +// page. +$conf['links'] = array(); + +// random_index_redirect: list of 'internal' links to use when no section is defined on index.php. +// An example is the best than a long explanation : +// +// for each link is associated a php condition +// '' condition is equivalent to 'return true;' +// $conf['random_index_redirect'] = array( +// PHPWG_ROOT_PATH.'index.php?/best_rated' => 'return true;', +// PHPWG_ROOT_PATH.'index.php?/recent_pics' => 'return is_a_guest();', +// PHPWG_ROOT_PATH.'random.php' => '', +// PHPWG_ROOT_PATH.'index.php?/categories' => '', +// ); +$conf['random_index_redirect'] = array(); + +// List of notes to display on all header page +// example $conf['header_notes'] = array('Test', 'Hello'); +$conf['header_notes'] = array(); + +// show_thumbnail_caption : on thumbnails page, show thumbnail captions ? +$conf['show_thumbnail_caption'] = true; + +// show_picture_name_on_title : on picture presentation page, show picture +// name ? +$conf['show_picture_name_on_title'] = true; + +// display_fromto: in subcatify mode, display the date creation bounds of a +// category. +$conf['display_fromto'] = false; + +// allow_random_representative : do you wish Piwigo to search among +// categories elements a new representative at each reload ? +// +// If false, an element is randomly or manually chosen to represent its +// category and remains the representative as long as an admin does not +// change it. +// +// Warning : setting this parameter to true is CPU consuming. Each time you +// change the value of this parameter from false to true, an administrator +// must update categories informations in screen [Admin > General > +// Maintenance]. +$conf['allow_random_representative'] = false; + +// allow_html_descriptions : authorize administrators to use HTML in +// category and element description. +$conf['allow_html_descriptions'] = true; + +// prefix_thumbnail : string before filename. Thumbnail's prefix must only +// contain characters among : a to z (case insensitive), "-" or "_". +$conf['prefix_thumbnail'] = 'TN-'; + +// users_page: how many users to display in screen +// Administration>Identification>Users? +$conf['users_page'] = 20; + +// image level permissions available in the admin interface +$conf['available_permission_levels'] = array(0,1,2,4,8); + +// mail_options: only set it true if you have a send mail warning with +// "options" parameter missing on mail() function execution. +$conf['mail_options'] = false; + +// send_bcc_mail_webmaster: send bcc mail to webmaster. Set true for debug +// or test. +$conf['send_bcc_mail_webmaster'] = false; + +// default_email_format: +// Define the default email format use to send email +// Value could be text/plain or text/html +$conf['default_email_format'] = 'text/html'; + +// define the name of sender mail: +// If value is empty, gallery title is used +$conf['mail_sender_name'] = ''; + +// smtp configuration +// (work if fsockopen function is allowed for smtp port) +// smtp_host: smtp server host +// if null, regular mail function is used +// format: hoststring[:port] +// exemple: smtp.pwg.net:21 +// smtp_user/smtp_password: user & password for smtp identication +$conf['smtp_host'] = ''; +$conf['smtp_user'] = ''; +$conf['smtp_password'] = ''; + + +// check_upgrade_feed: check if there are database upgrade required. Set to +// true, a message will strongly encourage you to upgrade your database if +// needed. +// +// This configuration parameter is set to true in BSF branch and to false +// elsewhere. +$conf['check_upgrade_feed'] = true; + +// rate_items: available rates for a picture +$conf['rate_items'] = array(0,1,2,3,4,5); + +// Define default method to use ('http' or 'html' in order to do redirect) +$conf['default_redirect_method'] = 'http'; + +// +-----------------------------------------------------------------------+ +// | metadata | +// +-----------------------------------------------------------------------+ + +// show_iptc: Show IPTC metadata on picture.php if asked by user +$conf['show_iptc'] = false; + +// show_iptc_mapping : is used for showing IPTC metadata on picture.php +// page. For each key of the array, you need to have the same key in the +// $lang array. For example, if my first key is 'iptc_keywords' (associated +// to '2#025') then you need to have $lang['iptc_keywords'] set in +// language/$user['language']/common.lang.php. If you don't have the lang +// var set, the key will be simply displayed +// +// To know how to associated iptc_field with their meaning, use +// tools/metadata.php +$conf['show_iptc_mapping'] = array( + 'iptc_keywords' => '2#025', + 'iptc_caption_writer' => '2#122', + 'iptc_byline_title' => '2#085', + 'iptc_caption' => '2#120' + ); + +// use_iptc: Use IPTC data during database synchronization with files +// metadata +$conf['use_iptc'] = false; + +// use_iptc_mapping : in which IPTC fields will Piwigo find image +// information ? This setting is used during metadata synchronisation. It +// associates a piwigo_images column name to a IPTC key +$conf['use_iptc_mapping'] = array( + 'keywords' => '2#025', + 'date_creation' => '2#055', + 'author' => '2#122', + 'name' => '2#005', + 'comment' => '2#120' + ); + +// show_exif: Show EXIF metadata on picture.php (table or line presentation +// avalaible) +$conf['show_exif'] = true; + +// show_exif_fields : in EXIF fields, you can choose to display fields in +// sub-arrays, for example ['COMPUTED']['ApertureFNumber']. for this, add +// 'COMPUTED;ApertureFNumber' in $conf['show_exif_fields'] +// +// The key displayed in picture.php will be $lang['exif_field_Make'] for +// example and if it exists. For compound fields, only take into account the +// last part : for key 'COMPUTED;ApertureFNumber', you need +// $lang['exif_field_ApertureFNumber'] +// +// for PHP version newer than 4.1.2 : +// $conf['show_exif_fields'] = array('CameraMake','CameraModel','DateTime'); +// +$conf['show_exif_fields'] = array( + 'Make', + 'Model', + 'DateTimeOriginal', + 'COMPUTED;ApertureFNumber' + ); + +// use_exif: Use EXIF data during database synchronization with files +// metadata +$conf['use_exif'] = true; + +// use_exif_mapping: same behaviour as use_iptc_mapping +$conf['use_exif_mapping'] = array( + 'date_creation' => 'DateTimeOriginal' + ); + +// +-----------------------------------------------------------------------+ +// | sessions | +// +-----------------------------------------------------------------------+ + +// session_use_cookies: specifies to use cookie to store +// the session id on client side +$conf['session_use_cookies'] = true; + +// session_use_only_cookies: specifies to only use cookie to store +// the session id on client side +$conf['session_use_only_cookies'] = true; + +// session_use_trans_sid: do not use transparent session id support +$conf['session_use_trans_sid'] = false; + +// session_name: specifies the name of the session which is used as cookie name +$conf['session_name'] = 'pwg_id'; + +// session_save_handler: comment the line below +// to use file handler for sessions. +$conf['session_save_handler'] = 'db'; + +// authorize_remembering : permits user to stay logged for a long time. It +// creates a cookie on client side. +$conf['authorize_remembering'] = true; + +// remember_me_name: specifies the name of the cookie used to stay logged +$conf['remember_me_name'] = 'pwg_remember'; + +// remember_me_length : time of validity for "remember me" cookies, in +// seconds. +$conf['remember_me_length'] = 5184000; + +// session_length : time of validity for normal session, in seconds. +$conf['session_length'] = 3600; + +// +-----------------------------------------------------------------------+ +// | debug | +// +-----------------------------------------------------------------------+ + +// show_queries : for debug purpose, show queries and execution times +$conf['show_queries'] = false; + +// show_gt : display generation time at the bottom of each page +$conf['show_gt'] = true; + +// debug_l10n : display a warning message each time an unset language key is +// accessed +$conf['debug_l10n'] = false; + +// activate template debugging - a new window will appear +$conf['debug_template'] = false; + +// die_on_sql_error: if an SQL query fails, should everything stop? +$conf['die_on_sql_error'] = true; + +// +-----------------------------------------------------------------------+ +// | authentication | +// +-----------------------------------------------------------------------+ + +// apache_authentication : use Apache authentication as reference instead of +// users table ? +$conf['apache_authentication'] = false; + +// users_table: which table is the reference for users? Can be a different +// table than Piwigo table +// +// If you decide to use another table than the default one, you need to +// prepare your database by deleting some datas : +// +// delete from piwigo_user_access; +// delete from piwigo_user_cache; +// delete from piwigo_user_feed; +// delete from piwigo_user_group; +// delete from piwigo_user_infos; +// delete from piwigo_sessions; +// delete from piwigo_rate; +// update piwigo_images set average_rate = null; +// delete from piwigo_caddie; +// delete from piwigo_favorites; +// +// All informations contained in these tables and column are related to +// piwigo_users table. +$conf['users_table'] = $prefixeTable.'users'; + +// Other tables can be changed, if you define associated constants +// Example: +// define('USER_INFOS_TABLE', 'pwg_main'.'user_infos'); + + +// user_fields : mapping between generic field names and table specific +// field names. For example, in PWG, the mail address is names +// "mail_address" and in punbb, it's called "email". +$conf['user_fields'] = array( + 'id' => 'id', + 'username' => 'username', + 'password' => 'password', + 'email' => 'mail_address' + ); + +// pass_convert : function to crypt or hash the clear user password to store +// it in the database +$conf['pass_convert'] = create_function('$s', 'return md5($s);'); + +// guest_id : id of the anonymous user +$conf['guest_id'] = 2; +// default_user_id : id of user used for default value +$conf['default_user_id'] = $conf['guest_id']; + +// webmaster_id : webmaster'id. +$conf['webmaster_id'] = 1; + +// allow to use adviser mode +$conf['allow_adviser'] = false; + +// does the guest have access ? +// (not a security feature, set your categories "private" too) +// If false it'll be redirected from index.php to identification.php +$conf['guest_access'] = true; + +// +-----------------------------------------------------------------------+ +// | upload | +// +-----------------------------------------------------------------------+ + +// upload_maxfilesize: maximum filesize for the uploaded pictures. In +// kilobytes. +$conf['upload_maxfilesize'] = 200; + +// upload_maxheight: maximum height authorized for the uploaded images. In +// pixels. +$conf['upload_maxheight'] = 800; + +// upload_maxwidth: maximum width authorized for the uploaded images. In +// pixels. +$conf['upload_maxwidth'] = 800; + +// upload_maxheight_thumbnail: maximum height authorized for the uploaded +// thumbnails +$conf['upload_maxheight_thumbnail'] = 128; + +// upload_maxwidth_thumbnail: maximum width authorized for the uploaded +// thumbnails +$conf['upload_maxwidth_thumbnail'] = 128; + +// +-----------------------------------------------------------------------+ +// | history | +// +-----------------------------------------------------------------------+ + +// nb_logs_page : how many logs to display on a page +$conf['nb_logs_page'] = 300; + +// +-----------------------------------------------------------------------+ +// | urls | +// +-----------------------------------------------------------------------+ + +// question_mark_in_urls : the generated urls contain a ? sign. This can be +// changed to false only if the server translates PATH_INFO variable +// (depends on the server AcceptPathInfo directive configuration) +$conf['question_mark_in_urls'] = true; + +// php_extension_in_urls : if true, the urls generated for picture and +// category will not contain the .php extension. This will work only if +// .htaccess defines Options +MultiViews parameter or url rewriting rules +// are active. +$conf['php_extension_in_urls'] = true; + +// category_url_style : one of 'id' (default) or 'id-name'. 'id-name' +// means that an simplified ascii represntation of the category name will +// appear in the url +$conf['category_url_style'] = 'id'; + +// picture_url_style : one of 'id' (default), 'id-file' or 'file'. 'id-file' +// or 'file' mean that the file name (without extension will appear in the +// url). Note that one aditionnal sql query will occur if 'file' is choosen. +// Note that you might experience navigation issues if you choose 'file' +// and your file names are not unique +$conf['picture_url_style'] = 'id'; + +// tag_url_style : one of 'id-tag' (default), 'id' or 'tag'. +// Note that if you choose 'tag' and the url (ascii) representation of your +// tags is not unique, all tags with the same url representation will be shown +$conf['tag_url_style'] = 'id-tag'; + +// +-----------------------------------------------------------------------+ +// | tags | +// +-----------------------------------------------------------------------+ + +// full_tag_cloud_items_number: number of tags to show in the full tag +// cloud. Only the most represented tags will be shown +$conf['full_tag_cloud_items_number'] = 200; + +// menubar_tag_cloud_items_number: number of tags to show in the tag +// cloud in the menubar. Only the most represented tags will be shown +$conf['menubar_tag_cloud_items_number'] = 100; + +// content_tag_cloud_items_number: number of tags to show in the tag +// cloud on the content page. Only the most represented tags will be shown +$conf['content_tag_cloud_items_number'] = 12; + +// tags_levels: number of levels to use for display. Each level is bind to a +// CSS class tagLevelX. +$conf['tags_levels'] = 5; + +// +-----------------------------------------------------------------------+ +// | Notification by mail | +// +-----------------------------------------------------------------------+ + +// Default Value for nbm user +$conf['nbm_default_value_user_enabled'] = false; + +// Search list user to send quickly (List all without to check news) +// More quickly but less fun to use +$conf['nbm_list_all_enabled_users_to_send'] = false; + +// Max time used on one pass in order to send mails. +// Timeout delay ratio. +$conf['nbm_max_treatment_timeout_percent'] = 0.8; + +// If timeout cannot be compite with nbm_max_treatment_timeout_percent, +// nbm_treatment_timeout_default is used by default +$conf['nbm_treatment_timeout_default'] = 20; + +// Parameters used in get_recent_post_dates for the 2 kind of notification +$conf['recent_post_dates'] = array( + 'RSS' => array('max_dates' => 5, 'max_elements' => 6, 'max_cats' => 6), + 'NBM' => array('max_dates' => 7, 'max_elements' => 3, 'max_cats' => 9) + ); + +// +-----------------------------------------------------------------------+ +// | Set admin layout | +// +-----------------------------------------------------------------------+ + +$conf['admin_layout'] = 'yoga/admin'; + +// should we load the active plugins ? true=Yes, false=No +$conf['enable_plugins']=true; + +// Web services are allowed (true) or completely forbidden (false) +$conf['allow_web_services'] = true; + +// Maximum number of images to be returned foreach call to the web service +$conf['ws_max_images_per_page'] = 500; + +// On Access control false / Admim Web Service need Php cURL extension +// Controls are done on public basis or +// if connected on member authorization basis +$conf['ws_access_control'] = false; + +// Additionnal controls are made based on Web Service Access Table +// Max returned rows number ( > 0 ) +$conf['ws_allowed_limit'] = array(1,2,3,5,10,25); + +// By default can be delayed by 0, 1, 2, 3, 5, 7, 14 or 30 days +// 0 it's Now(), don't remove that one +$conf['ws_postponed_start'] = array(0,1,2,3,5,7,14,30); /* In days */ + +// By default 10, 5, 2, 1 year(s) or 6, 3, 1 month(s) +// or 15, 10, 7, 5, 1, 0 day(s) +// 0 it's temporary closed (Useful for one access) +$conf['ws_durations'] = array(3650,1825,730,365,182,91,30,15,10,7,5,1,0); + +// +-----------------------------------------------------------------------+ +// | Filter | +// +-----------------------------------------------------------------------+ +// $conf['filter_pages'] contains configuration for each pages +// o If values are not defined for a specific page, default value are used +// o Array is composed by the basename of each page without extention +// o List of value names: +// - used: filter function are used +// (if false nothing is done [start, cancel, stop, ...] +// - cancel: cancel current started filter +// - add_notes: add notes about current started filter on the header +// o Empty configuration in order to disable completely filter functions +// No filter, No icon,... +// $conf['filter_pages'] = array(); +$conf['filter_pages'] = array + ( + // Default page + 'default' => array( + 'used' => true, 'cancel' => false, 'add_notes' => false), + // Real pages + 'index' => array('add_notes' => true), + 'tags' => array('add_notes' => true), + 'search' => array('add_notes' => true), + 'comments' => array('add_notes' => true), + 'admin' => array('used' => false), + 'feed' => array('used' => false), + 'notification' => array('used' => false), + 'nbm' => array('used' => false), + 'popuphelp' => array('used' => false), + 'profile' => array('used' => false), + 'web_service' => array('used' => false), + 'ws' => array('used' => false), + 'identification' => array('cancel' => true), + 'install' => array('cancel' => true), + 'password' => array('cancel' => true), + 'register' => array('cancel' => true), + 'upgrade_feed' => array('cancel' => true), + ); + +// +-----------------------------------------------------------------------+ +// | Slideshow | +// +-----------------------------------------------------------------------+ +// slideshow_period : waiting time in seconds before loading a new page +// during automated slideshow +// slideshow_period_min, slideshow_period_max are bounds of slideshow_period +// slideshow_period_step is the step of navigation between min and max +$conf['slideshow_period_min'] = 1; +$conf['slideshow_period_max'] = 10; +$conf['slideshow_period_step'] = 1; +$conf['slideshow_period'] = 4; + +// slideshow_repeat : slideshow loops on pictures +$conf['slideshow_repeat'] = true; + +// $conf['light_slideshow'] indicates to use slideshow.tpl in state of +// picture.tpl for slideshow +// Take care to have slideshow.tpl in all available templates +// Or set it false. +// Check if Picture's plugins are compliant with it +// Every plugin from 1.7 would be design to manage light_slideshow case. +$conf['light_slideshow'] = true; + +// the local data directory is used to store data such as compiled templates +// or other plugin variables etc +$conf['local_data_dir'] = dirname(dirname(__FILE__)).'/_data'; + +// if true, some language strings are replaced during template compilation +// (insted of template output). this results in better performance. however +// any change in the language file will not be propagated until you purge +// the compiled templates from the admin / maintenance menu +$conf['compiled_template_cache_language'] = false; + +?>
\ No newline at end of file diff --git a/BSF/include/constants.php b/BSF/include/constants.php new file mode 100644 index 000000000..42854a9d4 --- /dev/null +++ b/BSF/include/constants.php @@ -0,0 +1,112 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// Default settings +define('PHPWG_VERSION', 'Butterfly'); +define('PHPWG_DOMAIN', 'phpwebgallery.net'); +define('PHPWG_URL', 'http://www.'.PHPWG_DOMAIN); +define('PEM_URL', 'http://' . PHPWG_DOMAIN . '/ext'); +define('PHPWG_DEFAULT_LANGUAGE', 'en_UK'); +define('PHPWG_DEFAULT_TEMPLATE', 'yoga/clear'); + +// Required versions +define('REQUIRED_PHP_VERSION', '5.0.0'); +define('REQUIRED_MYSQL_VERSION', '4.1.22'); + +// Error codes +define('GENERAL_MESSAGE', 200); +define('GENERAL_ERROR', 202); +define('CRITICAL_MESSAGE', 203); +define('CRITICAL_ERROR', 204); + +// Access codes +define('ACCESS_FREE', 0); +define('ACCESS_GUEST', 1); +define('ACCESS_CLASSIC', 2); +define('ACCESS_ADMINISTRATOR', 3); +define('ACCESS_WEBMASTER', 4); +define('ACCESS_CLOSED', 5); + +// Table names +if (!defined('CATEGORIES_TABLE')) + define('CATEGORIES_TABLE', $prefixeTable.'categories'); +if (!defined('COMMENTS_TABLE')) + define('COMMENTS_TABLE', $prefixeTable.'comments'); +if (!defined('CONFIG_TABLE')) + define('CONFIG_TABLE', $prefixeTable.'config'); +if (!defined('FAVORITES_TABLE')) + define('FAVORITES_TABLE', $prefixeTable.'favorites'); +if (!defined('GROUP_ACCESS_TABLE')) + define('GROUP_ACCESS_TABLE', $prefixeTable.'group_access'); +if (!defined('GROUPS_TABLE')) + define('GROUPS_TABLE', $prefixeTable.'groups'); +if (!defined('HISTORY_TABLE')) + define('HISTORY_TABLE', $prefixeTable.'history'); +if (!defined('HISTORY_SUMMARY_TABLE')) + define('HISTORY_SUMMARY_TABLE', $prefixeTable.'history_summary'); +if (!defined('IMAGE_CATEGORY_TABLE')) + define('IMAGE_CATEGORY_TABLE', $prefixeTable.'image_category'); +if (!defined('IMAGES_TABLE')) + define('IMAGES_TABLE', $prefixeTable.'images'); +if (!defined('SESSIONS_TABLE')) + define('SESSIONS_TABLE', $prefixeTable.'sessions'); +if (!defined('SITES_TABLE')) + define('SITES_TABLE', $prefixeTable.'sites'); +if (!defined('USER_ACCESS_TABLE')) + define('USER_ACCESS_TABLE', $prefixeTable.'user_access'); +if (!defined('USER_GROUP_TABLE')) + define('USER_GROUP_TABLE', $prefixeTable.'user_group'); +if (!defined('USERS_TABLE')) + define('USERS_TABLE', $conf['users_table']); +if (!defined('USER_INFOS_TABLE')) + define('USER_INFOS_TABLE', $prefixeTable.'user_infos'); +if (!defined('USER_FEED_TABLE')) + define('USER_FEED_TABLE', $prefixeTable.'user_feed'); +if (!defined('WAITING_TABLE')) + define('WAITING_TABLE', $prefixeTable.'waiting'); +if (!defined('RATE_TABLE')) + define('RATE_TABLE', $prefixeTable.'rate'); +if (!defined('USER_CACHE_TABLE')) + define('USER_CACHE_TABLE', $prefixeTable.'user_cache'); +if (!defined('USER_CACHE_CATEGORIES_TABLE')) + define('USER_CACHE_CATEGORIES_TABLE', $prefixeTable.'user_cache_categories'); +if (!defined('CADDIE_TABLE')) + define('CADDIE_TABLE', $prefixeTable.'caddie'); +if (!defined('UPGRADE_TABLE')) + define('UPGRADE_TABLE', $prefixeTable.'upgrade'); +if (!defined('SEARCH_TABLE')) + define('SEARCH_TABLE', $prefixeTable.'search'); +if (!defined('USER_MAIL_NOTIFICATION_TABLE')) + define('USER_MAIL_NOTIFICATION_TABLE', $prefixeTable.'user_mail_notification'); +if (!defined('TAGS_TABLE')) + define('TAGS_TABLE', $prefixeTable.'tags'); +if (!defined('IMAGE_TAG_TABLE')) + define('IMAGE_TAG_TABLE', $prefixeTable.'image_tag'); +if (!defined('PLUGINS_TABLE')) + define('PLUGINS_TABLE', $prefixeTable.'plugins'); +if (!defined('WEB_SERVICES_ACCESS_TABLE')) + define('WEB_SERVICES_ACCESS_TABLE', $prefixeTable.'ws_access'); +if (!defined('OLD_PERMALINKS_TABLE')) + define('OLD_PERMALINKS_TABLE', $prefixeTable.'old_permalinks'); + +?> diff --git a/BSF/include/feedcreator.class.php b/BSF/include/feedcreator.class.php new file mode 100644 index 000000000..f274b8417 --- /dev/null +++ b/BSF/include/feedcreator.class.php @@ -0,0 +1,1541 @@ +<?php +/*************************************************************************** + +FeedCreator class v1.7.2 +originally (c) Kai Blankenhorn +www.bitfolge.de +kaib@bitfolge.de +v1.3 work by Scott Reynen (scott@randomchaos.com) and Kai Blankenhorn +v1.5 OPML support by Dirk Clemens + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +**************************************************************************** + + +Changelog: + +v1.7.2 10-11-04 + license changed to LGPL + +v1.7.1 + fixed a syntax bug + fixed left over debug code + +v1.7 07-18-04 + added HTML and JavaScript feeds (configurable via CSS) (thanks to Pascal Van Hecke) + added HTML descriptions for all feed formats (thanks to Pascal Van Hecke) + added a switch to select an external stylesheet (thanks to Pascal Van Hecke) + changed default content-type to application/xml + added character encoding setting + fixed numerous smaller bugs (thanks to Sören Fuhrmann of golem.de) + improved changing ATOM versions handling (thanks to August Trometer) + improved the UniversalFeedCreator's useCached method (thanks to Sören Fuhrmann of golem.de) + added charset output in HTTP headers (thanks to Sören Fuhrmann of golem.de) + added Slashdot namespace to RSS 1.0 (thanks to Sören Fuhrmann of golem.de) + +v1.6 05-10-04 + added stylesheet to RSS 1.0 feeds + fixed generator comment (thanks Kevin L. Papendick and Tanguy Pruvot) + fixed RFC822 date bug (thanks Tanguy Pruvot) + added TimeZone customization for RFC8601 (thanks Tanguy Pruvot) + fixed Content-type could be empty (thanks Tanguy Pruvot) + fixed author/creator in RSS1.0 (thanks Tanguy Pruvot) + +v1.6 beta 02-28-04 + added Atom 0.3 support (not all features, though) + improved OPML 1.0 support (hopefully - added more elements) + added support for arbitrary additional elements (use with caution) + code beautification :-) + considered beta due to some internal changes + +v1.5.1 01-27-04 + fixed some RSS 1.0 glitches (thanks to Stéphane Vanpoperynghe) + fixed some inconsistencies between documentation and code (thanks to Timothy Martin) + +v1.5 01-06-04 + added support for OPML 1.0 + added more documentation + +v1.4 11-11-03 + optional feed saving and caching + improved documentation + minor improvements + +v1.3 10-02-03 + renamed to FeedCreator, as it not only creates RSS anymore + added support for mbox + tentative support for echo/necho/atom/pie/??? + +v1.2 07-20-03 + intelligent auto-truncating of RSS 0.91 attributes + don't create some attributes when they're not set + documentation improved + fixed a real and a possible bug with date conversions + code cleanup + +v1.1 06-29-03 + added images to feeds + now includes most RSS 0.91 attributes + added RSS 2.0 feeds + +v1.0 06-24-03 + initial release + + + +***************************************************************************/ + +/*** GENERAL USAGE ********************************************************* + +include("feedcreator.class.php"); + +$rss = new UniversalFeedCreator(); +$rss->useCached(); // use cached version if age<1 hour +$rss->title = "PHP news"; +$rss->description = "daily news from the PHP scripting world"; + +//optional +$rss->descriptionTruncSize = 500; +$rss->descriptionHtmlSyndicated = true; + +$rss->link = "http://www.dailyphp.net/news"; +$rss->syndicationURL = "http://www.dailyphp.net/".$_SERVER["PHP_SELF"]; + +$image = new FeedImage(); +$image->title = "dailyphp.net logo"; +$image->url = "http://www.dailyphp.net/images/logo.gif"; +$image->link = "http://www.dailyphp.net"; +$image->description = "Feed provided by dailyphp.net. Click to visit."; + +//optional +$image->descriptionTruncSize = 500; +$image->descriptionHtmlSyndicated = true; + +$rss->image = $image; + +// get your news items from somewhere, e.g. your database: +mysql_select_db($dbHost, $dbUser, $dbPass); +$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); +while ($data = mysql_fetch_object($res)) { + $item = new FeedItem(); + $item->title = $data->title; + $item->link = $data->url; + $item->description = $data->short; + + //optional + item->descriptionTruncSize = 500; + item->descriptionHtmlSyndicated = true; + + $item->date = $data->newsdate; + $item->source = "http://www.dailyphp.net"; + $item->author = "John Doe"; + + $rss->addItem($item); +} + +// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1 (deprecated), +// MBOX, OPML, ATOM, ATOM0.3, HTML, JS +echo $rss->saveFeed("RSS1.0", "news/feed.xml"); + + +*************************************************************************** +* A little setup * +**************************************************************************/ + +// your local timezone, set to "" to disable or for GMT +define("TIME_ZONE","+00:00"); + + + + +/** + * Version string. + **/ +define("FEEDCREATOR_VERSION", "FeedCreator 1.7.2"); + + + +/** + * A FeedItem is a part of a FeedCreator feed. + * + * @author Kai Blankenhorn <kaib@bitfolge.de> + * @since 1.3 + */ +class FeedItem extends HtmlDescribable { + /** + * Mandatory attributes of an item. + */ + var $title, $description, $link; + + /** + * Optional attributes of an item. + */ + var $author, $authorEmail, $image, $category, $comments, $guid, $source, $creator; + + /** + * Publishing date of an item. May be in one of the following formats: + * + * RFC 822: + * "Mon, 20 Jan 03 18:05:41 +0400" + * "20 Jan 03 18:05:41 +0000" + * + * ISO 8601: + * "2003-01-20T18:05:41+04:00" + * + * Unix: + * 1043082341 + */ + var $date; + + /** + * Any additional elements to include as an assiciated array. All $key => $value pairs + * will be included unencoded in the feed item in the form + * <$key>$value</$key> + * Again: No encoding will be used! This means you can invalidate or enhance the feed + * if $value contains markup. This may be abused to embed tags not implemented by + * the FeedCreator class used. + */ + var $additionalElements = Array(); + + // on hold + // var $source; +} + + + +/** + * An FeedImage may be added to a FeedCreator feed. + * @author Kai Blankenhorn <kaib@bitfolge.de> + * @since 1.3 + */ +class FeedImage extends HtmlDescribable { + /** + * Mandatory attributes of an image. + */ + var $title, $url, $link; + + /** + * Optional attributes of an image. + */ + var $width, $height, $description; +} + + + +/** + * An HtmlDescribable is an item within a feed that can have a description that may + * include HTML markup. + */ +class HtmlDescribable { + /** + * Indicates whether the description field should be rendered in HTML. + */ + var $descriptionHtmlSyndicated; + + /** + * Indicates whether and to how many characters a description should be truncated. + */ + var $descriptionTruncSize; + + /** + * Returns a formatted description field, depending on descriptionHtmlSyndicated and + * $descriptionTruncSize properties + * @return string the formatted description + */ + function getDescription() { + $descriptionField = new FeedHtmlField($this->description); + $descriptionField->syndicateHtml = $this->descriptionHtmlSyndicated; + $descriptionField->truncSize = $this->descriptionTruncSize; + return $descriptionField->output(); + } + +} + + +/** + * An FeedHtmlField describes and generates + * a feed, item or image html field (probably a description). Output is + * generated based on $truncSize, $syndicateHtml properties. + * @author Pascal Van Hecke <feedcreator.class.php@vanhecke.info> + * @version 1.6 + */ +class FeedHtmlField { + /** + * Mandatory attributes of a FeedHtmlField. + */ + var $rawFieldContent; + + /** + * Optional attributes of a FeedHtmlField. + * + */ + var $truncSize, $syndicateHtml; + + /** + * Creates a new instance of FeedHtmlField. + * @param $string: if given, sets the rawFieldContent property + */ + function FeedHtmlField($parFieldContent) { + if ($parFieldContent) { + $this->rawFieldContent = $parFieldContent; + } + } + + + /** + * Creates the right output, depending on $truncSize, $syndicateHtml properties. + * @return string the formatted field + */ + function output() { + // when field available and syndicated in html we assume + // - valid html in $rawFieldContent and we enclose in CDATA tags + // - no truncation (truncating risks producing invalid html) + if (!$this->rawFieldContent) { + $result = ""; + } elseif ($this->syndicateHtml) { + $result = "<![CDATA[".$this->rawFieldContent."]]>"; + } else { + if ($this->truncSize and is_int($this->truncSize)) { + $result = FeedCreator::iTrunc(htmlspecialchars($this->rawFieldContent),$this->truncSize); + } else { + $result = htmlspecialchars($this->rawFieldContent); + } + } + return $result; + } + +} + + + +/** + * UniversalFeedCreator lets you choose during runtime which + * format to build. + * For general usage of a feed class, see the FeedCreator class + * below or the example above. + * + * @since 1.3 + * @author Kai Blankenhorn <kaib@bitfolge.de> + */ +class UniversalFeedCreator extends FeedCreator { + var $_feed; + + function _setFormat($format) { + switch (strtoupper($format)) { + + case "2.0": + // fall through + case "RSS2.0": + $this->_feed = new RSSCreator20(); + break; + + case "1.0": + // fall through + case "RSS1.0": + $this->_feed = new RSSCreator10(); + break; + + case "0.91": + // fall through + case "RSS0.91": + $this->_feed = new RSSCreator091(); + break; + + case "PIE0.1": + $this->_feed = new PIECreator01(); + break; + + case "MBOX": + $this->_feed = new MBOXCreator(); + break; + + case "OPML": + $this->_feed = new OPMLCreator(); + break; + + case "ATOM": + // fall through: always the latest ATOM version + + case "ATOM0.3": + $this->_feed = new AtomCreator03(); + break; + + case "HTML": + $this->_feed = new HTMLCreator(); + break; + + case "JS": + // fall through + case "JAVASCRIPT": + $this->_feed = new JSCreator(); + break; + + default: + $this->_feed = new RSSCreator091(); + break; + } + + $vars = get_object_vars($this); + foreach ($vars as $key => $value) { + // prevent overwriting of properties "contentType", "encoding"; do not copy "_feed" itself + if (!in_array($key, array("_feed", "contentType"/*PWG, "encoding"*/))) { + $this->_feed->{$key} = $this->{$key}; + } + } + } + + /** + * Creates a syndication feed based on the items previously added. + * + * @see FeedCreator::addItem() + * @param string format format the feed should comply to. Valid values are: + * "PIE0.1", "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3", "HTML", "JS" + * @return string the contents of the feed. + */ + function createFeed($format = "RSS0.91") { + $this->_setFormat($format); + return $this->_feed->createFeed(); + } + + + + /** + * Saves this feed as a file on the local disk. After the file is saved, an HTTP redirect + * header may be sent to redirect the use to the newly created file. + * @since 1.4 + * + * @param string format format the feed should comply to. Valid values are: + * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM", "ATOM0.3", "HTML", "JS" + * @param string filename optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). + * @param boolean displayContents optional send the content of the file or not. If true, the file will be sent in the body of the response. + */ + function saveFeed($format="RSS0.91", $filename="", $displayContents=true) { + $this->_setFormat($format); + $this->_feed->saveFeed($filename, $displayContents); + } + + + /** + * Turns on caching and checks if there is a recent version of this feed in the cache. + * If there is, an HTTP redirect header is sent. + * To effectively use caching, you should create the FeedCreator object and call this method + * before anything else, especially before you do the time consuming task to build the feed + * (web fetching, for example). + * + * @param string format format the feed should comply to. Valid values are: + * "PIE0.1" (deprecated), "mbox", "RSS0.91", "RSS1.0", "RSS2.0", "OPML", "ATOM0.3". + * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). + * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour) + */ + function useCached($format="RSS0.91", $filename="", $timeout=3600) { + $this->_setFormat($format); + $this->_feed->useCached($filename, $timeout); + } + +} + + +/** + * FeedCreator is the abstract base implementation for concrete + * implementations that implement a specific format of syndication. + * + * @abstract + * @author Kai Blankenhorn <kaib@bitfolge.de> + * @since 1.4 + */ +class FeedCreator extends HtmlDescribable { + + /** + * Mandatory attributes of a feed. + */ + var $title, $description, $link; + + + /** + * Optional attributes of a feed. + */ + var $syndicationURL, $image, $language, $copyright, $pubDate, $lastBuildDate, $editor, $editorEmail, $webmaster, $category, $docs, $ttl, $rating, $skipHours, $skipDays; + + /** + * The url of the external xsl stylesheet used to format the naked rss feed. + * Ignored in the output when empty. + */ + var $xslStyleSheet = ""; + + + /** + * @access private + */ + var $items = Array(); + + + /** + * This feed's MIME content type. + * @since 1.4 + * @access private + */ + var $contentType = "application/xml"; + + + /** + * This feed's character encoding. + * @since 1.6.1 + **/ + var $encoding = "ISO-8859-1"; + + + /** + * Any additional elements to include as an assiciated array. All $key => $value pairs + * will be included unencoded in the feed in the form + * <$key>$value</$key> + * Again: No encoding will be used! This means you can invalidate or enhance the feed + * if $value contains markup. This may be abused to embed tags not implemented by + * the FeedCreator class used. + */ + var $additionalElements = Array(); + + + /** + * Adds an FeedItem to the feed. + * + * @param object FeedItem $item The FeedItem to add to the feed. + * @access public + */ + function addItem($item) { + $this->items[] = $item; + } + + + /** + * Truncates a string to a certain length at the most sensible point. + * First, if there's a '.' character near the end of the string, the string is truncated after this character. + * If there is no '.', the string is truncated after the last ' ' character. + * If the string is truncated, " ..." is appended. + * If the string is already shorter than $length, it is returned unchanged. + * + * @static + * @param string string A string to be truncated. + * @param int length the maximum length the string should be truncated to + * @return string the truncated string + */ + function iTrunc($string, $length) { + if (strlen($string)<=$length) { + return $string; + } + + $pos = strrpos($string,"."); + if ($pos>=$length-4) { + $string = substr($string,0,$length-4); + $pos = strrpos($string,"."); + } + if ($pos>=$length*0.4) { + return substr($string,0,$pos+1)." ..."; + } + + $pos = strrpos($string," "); + if ($pos>=$length-4) { + $string = substr($string,0,$length-4); + $pos = strrpos($string," "); + } + if ($pos>=$length*0.4) { + return substr($string,0,$pos)." ..."; + } + + return substr($string,0,$length-4)." ..."; + + } + + + /** + * Creates a comment indicating the generator of this feed. + * The format of this comment seems to be recognized by + * Syndic8.com. + */ + function _createGeneratorComment() { + return "<!-- generator=\"".FEEDCREATOR_VERSION."\" -->\n"; + } + + + /** + * Creates a string containing all additional elements specified in + * $additionalElements. + * @param elements array an associative array containing key => value pairs + * @param indentString string a string that will be inserted before every generated line + * @return string the XML tags corresponding to $additionalElements + */ + function _createAdditionalElements($elements, $indentString="") { + $ae = ""; + if (is_array($elements)) { + foreach($elements AS $key => $value) { + $ae.= $indentString."<$key>$value</$key>\n"; + } + } + return $ae; + } + + function _createStylesheetReferences() { + $xml = ""; + if (isset($this->cssStyleSheet)) $xml .= "<?xml-stylesheet href=\"".$this->cssStyleSheet."\" type=\"text/css\"?>\n"; + if ($this->xslStyleSheet) $xml .= "<?xml-stylesheet href=\"".$this->xslStyleSheet."\" type=\"text/xsl\"?>\n"; + return $xml; + } + + + /** + * Builds the feed's text. + * @abstract + * @return string the feed's complete text + */ + function createFeed() { + } + + /** + * Generate a filename for the feed cache file. The result will be $_SERVER["PHP_SELF"] with the extension changed to .xml. + * For example: + * + * echo $_SERVER["PHP_SELF"]."\n"; + * echo FeedCreator::_generateFilename(); + * + * would produce: + * + * /rss/latestnews.php + * latestnews.xml + * + * @return string the feed cache filename + * @since 1.4 + * @access private + */ + function _generateFilename() { + $fileInfo = pathinfo($_SERVER["PHP_SELF"]); + return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".xml"; + } + + + /** + * @since 1.4 + * @access private + */ + function _redirect($filename) { + // attention, heavily-commented-out-area + + // maybe use this in addition to file time checking + //Header("Expires: ".date("r",time()+$this->_timeout)); + + /* no caching at all, doesn't seem to work as good: + Header("Cache-Control: no-cache"); + Header("Pragma: no-cache"); + */ + + // HTTP redirect, some feed readers' simple HTTP implementations don't follow it + //Header("Location: ".$filename); + + Header("Content-Type: ".$this->contentType."; charset=".$this->encoding."; filename=".basename($filename)); + Header("Content-Disposition: inline; filename=".basename($filename)); + readfile($filename, "r"); + die(); + } + + /** + * Turns on caching and checks if there is a recent version of this feed in the cache. + * If there is, an HTTP redirect header is sent. + * To effectively use caching, you should create the FeedCreator object and call this method + * before anything else, especially before you do the time consuming task to build the feed + * (web fetching, for example). + * @since 1.4 + * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). + * @param timeout int optional the timeout in seconds before a cached version is refreshed (defaults to 3600 = 1 hour) + */ + function useCached($filename="", $timeout=3600) { + $this->_timeout = $timeout; + if ($filename=="") { + $filename = $this->_generateFilename(); + } + if (file_exists($filename) AND (time()-filemtime($filename) < $timeout)) { + $this->_redirect($filename); + } + } + + + /** + * Saves this feed as a file on the local disk. After the file is saved, a redirect + * header may be sent to redirect the user to the newly created file. + * @since 1.4 + * + * @param filename string optional the filename where a recent version of the feed is saved. If not specified, the filename is $_SERVER["PHP_SELF"] with the extension changed to .xml (see _generateFilename()). + * @param redirect boolean optional send an HTTP redirect header or not. If true, the user will be automatically redirected to the created file. + */ + function saveFeed($filename="", $displayContents=true) { + if ($filename=="") { + $filename = $this->_generateFilename(); + } + $feedFile = fopen($filename, "w+"); + if ($feedFile) { + fputs($feedFile,$this->createFeed()); + fclose($feedFile); + if ($displayContents) { + $this->_redirect($filename); + } + } else { + echo "<br /><b>Error creating feed file, please check write permissions.</b><br />"; + } + } + +} + + +/** + * FeedDate is an internal class that stores a date for a feed or feed item. + * Usually, you won't need to use this. + */ +class FeedDate { + var $unix; + + /** + * Creates a new instance of FeedDate representing a given date. + * Accepts RFC 822, ISO 8601 date formats as well as unix time stamps. + * @param mixed $dateString optional the date this FeedDate will represent. If not specified, the current date and time is used. + */ + function FeedDate($dateString="") { + if ($dateString=="") $dateString = date("r"); + + if (is_integer($dateString)) { + $this->unix = $dateString; + return; + } + if (preg_match("~(?:(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun),\\s+)?(\\d{1,2})\\s+([a-zA-Z]{3})\\s+(\\d{4})\\s+(\\d{2}):(\\d{2}):(\\d{2})\\s+(.*)~",$dateString,$matches)) { + $months = Array("Jan"=>1,"Feb"=>2,"Mar"=>3,"Apr"=>4,"May"=>5,"Jun"=>6,"Jul"=>7,"Aug"=>8,"Sep"=>9,"Oct"=>10,"Nov"=>11,"Dec"=>12); + $this->unix = mktime($matches[4],$matches[5],$matches[6],$months[$matches[2]],$matches[1],$matches[3]); + if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') { + $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60; + } else { + if (strlen($matches[7])==1) { + $oneHour = 3600; + $ord = ord($matches[7]); + if ($ord < ord("M")) { + $tzOffset = (ord("A") - $ord - 1) * $oneHour; + } elseif ($ord >= ord("M") AND $matches[7]!="Z") { + $tzOffset = ($ord - ord("M")) * $oneHour; + } elseif ($matches[7]=="Z") { + $tzOffset = 0; + } + } + switch ($matches[7]) { + case "UT": + case "GMT": $tzOffset = 0; + } + } + $this->unix += $tzOffset; + return; + } + if (preg_match("~(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(.*)~",$dateString,$matches)) { + $this->unix = mktime($matches[4],$matches[5],$matches[6],$matches[2],$matches[3],$matches[1]); + if (substr($matches[7],0,1)=='+' OR substr($matches[7],0,1)=='-') { + $tzOffset = (substr($matches[7],0,3) * 60 + substr($matches[7],-2)) * 60; + } else { + if ($matches[7]=="Z") { + $tzOffset = 0; + } + } + $this->unix += $tzOffset; + return; + } + $this->unix = 0; + } + + /** + * Gets the date stored in this FeedDate as an RFC 822 date. + * + * @return a date in RFC 822 format + */ + function rfc822() { + //return gmdate("r",$this->unix); + $date = gmdate("D, d M Y H:i:s", $this->unix); + if (TIME_ZONE!="") $date .= " ".str_replace(":","",TIME_ZONE); + return $date; + } + + /** + * Gets the date stored in this FeedDate as an ISO 8601 date. + * + * @return a date in ISO 8601 format + */ + function iso8601() { + $date = gmdate("Y-m-d\TH:i:sO",$this->unix); + $date = substr($date,0,22) . ':' . substr($date,-2); + if (TIME_ZONE!="") $date = str_replace("+00:00",TIME_ZONE,$date); + return $date; + } + + /** + * Gets the date stored in this FeedDate as unix time stamp. + * + * @return a date as a unix time stamp + */ + function unix() { + return $this->unix; + } +} + + +/** + * RSSCreator10 is a FeedCreator that implements RDF Site Summary (RSS) 1.0. + * + * @see http://www.purl.org/rss/1.0/ + * @since 1.3 + * @author Kai Blankenhorn <kaib@bitfolge.de> + */ +class RSSCreator10 extends FeedCreator { + + /** + * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0. + * The feed will contain all items previously added in the same order. + * @return string the feed's complete text + */ + function createFeed() { + $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n"; + $feed.= $this->_createGeneratorComment(); + if ($this->cssStyleSheet=="") { + $cssStyleSheet = "http://www.w3.org/2000/08/w3c-synd/style.css"; + } + $feed.= $this->_createStylesheetReferences(); + $feed.= "<rdf:RDF\n"; + $feed.= " xmlns=\"http://purl.org/rss/1.0/\"\n"; + $feed.= " xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n"; + $feed.= " xmlns:slash=\"http://purl.org/rss/1.0/modules/slash/\"\n"; + $feed.= " xmlns:dc=\"http://purl.org/dc/elements/1.1/\">\n"; + $feed.= " <channel rdf:about=\"".$this->syndicationURL."\">\n"; + $feed.= " <title>".htmlspecialchars($this->title)."</title>\n"; + $feed.= " <description>".htmlspecialchars($this->description)."</description>\n"; + $feed.= " <link>".$this->link."</link>\n"; + if ($this->image!=null) { + $feed.= " <image rdf:resource=\"".$this->image->url."\" />\n"; + } + $now = new FeedDate(); + $feed.= " <dc:date>".htmlspecialchars($now->iso8601())."</dc:date>\n"; + $feed.= " <items>\n"; + $feed.= " <rdf:Seq>\n"; + for ($i=0;$i<count($this->items);$i++) { + $feed.= " <rdf:li rdf:resource=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n"; + } + $feed.= " </rdf:Seq>\n"; + $feed.= " </items>\n"; + $feed.= " </channel>\n"; + if ($this->image!=null) { + $feed.= " <image rdf:about=\"".$this->image->url."\">\n"; + $feed.= " <title>".$this->image->title."</title>\n"; + $feed.= " <link>".$this->image->link."</link>\n"; + $feed.= " <url>".$this->image->url."</url>\n"; + $feed.= " </image>\n"; + } + $feed.= $this->_createAdditionalElements($this->additionalElements, " "); + + for ($i=0;$i<count($this->items);$i++) { + $feed.= " <item rdf:about=\"".htmlspecialchars($this->items[$i]->link)."\">\n"; + //$feed.= " <dc:type>Posting</dc:type>\n"; + $feed.= " <dc:format>text/html</dc:format>\n"; + if ($this->items[$i]->date!=null) { + $itemDate = new FeedDate($this->items[$i]->date); + $feed.= " <dc:date>".htmlspecialchars($itemDate->iso8601())."</dc:date>\n"; + } + if ($this->items[$i]->source!="") { + $feed.= " <dc:source>".htmlspecialchars($this->items[$i]->source)."</dc:source>\n"; + } + if ($this->items[$i]->author!="") { + $feed.= " <dc:creator>".htmlspecialchars($this->items[$i]->author)."</dc:creator>\n"; + } + $feed.= " <title>".htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r"," ")))."</title>\n"; + $feed.= " <link>".htmlspecialchars($this->items[$i]->link)."</link>\n"; + $feed.= " <description>".htmlspecialchars($this->items[$i]->description)."</description>\n"; + $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); + $feed.= " </item>\n"; + } + $feed.= "</rdf:RDF>\n"; + return $feed; + } +} + + + +/** + * RSSCreator091 is a FeedCreator that implements RSS 0.91 Spec, revision 3. + * + * @see http://my.netscape.com/publish/formats/rss-spec-0.91.html + * @since 1.3 + * @author Kai Blankenhorn <kaib@bitfolge.de> + */ +class RSSCreator091 extends FeedCreator { + + /** + * Stores this RSS feed's version number. + * @access private + */ + var $RSSVersion; + + function RSSCreator091() { + $this->_setRSSVersion("0.91"); + $this->contentType = "application/rss+xml"; + } + + /** + * Sets this RSS feed's version number. + * @access private + */ + function _setRSSVersion($version) { + $this->RSSVersion = $version; + } + + /** + * Builds the RSS feed's text. The feed will be compliant to RDF Site Summary (RSS) 1.0. + * The feed will contain all items previously added in the same order. + * @return string the feed's complete text + */ + function createFeed() { + $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n"; + $feed.= $this->_createGeneratorComment(); + $feed.= $this->_createStylesheetReferences(); + $feed.= "<rss version=\"".$this->RSSVersion."\">\n"; + $feed.= " <channel>\n"; + $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n"; + $this->descriptionTruncSize = 500; + $feed.= " <description>".$this->getDescription()."</description>\n"; + $feed.= " <link>".$this->link."</link>\n"; + $now = new FeedDate(); + $feed.= " <lastBuildDate>".htmlspecialchars($now->rfc822())."</lastBuildDate>\n"; + $feed.= " <generator>".FEEDCREATOR_VERSION."</generator>\n"; + + if ($this->image!=null) { + $feed.= " <image>\n"; + $feed.= " <url>".$this->image->url."</url>\n"; + $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars($this->image->title),100)."</title>\n"; + $feed.= " <link>".$this->image->link."</link>\n"; + if ($this->image->width!="") { + $feed.= " <width>".$this->image->width."</width>\n"; + } + if ($this->image->height!="") { + $feed.= " <height>".$this->image->height."</height>\n"; + } + if ($this->image->description!="") { + $feed.= " <description>".$this->image->getDescription()."</description>\n"; + } + $feed.= " </image>\n"; + } + if ($this->language!="") { + $feed.= " <language>".$this->language."</language>\n"; + } + if ($this->copyright!="") { + $feed.= " <copyright>".FeedCreator::iTrunc(htmlspecialchars($this->copyright),100)."</copyright>\n"; + } + if ($this->editor!="") { + $feed.= " <managingEditor>".FeedCreator::iTrunc(htmlspecialchars($this->editor),100)."</managingEditor>\n"; + } + if ($this->webmaster!="") { + $feed.= " <webMaster>".FeedCreator::iTrunc(htmlspecialchars($this->webmaster),100)."</webMaster>\n"; + } + if ($this->pubDate!="") { + $pubDate = new FeedDate($this->pubDate); + $feed.= " <pubDate>".htmlspecialchars($pubDate->rfc822())."</pubDate>\n"; + } + if ($this->category!="") { + $feed.= " <category>".htmlspecialchars($this->category)."</category>\n"; + } + if ($this->docs!="") { + $feed.= " <docs>".FeedCreator::iTrunc(htmlspecialchars($this->docs),500)."</docs>\n"; + } + if ($this->ttl!="") { + $feed.= " <ttl>".htmlspecialchars($this->ttl)."</ttl>\n"; + } + if ($this->rating!="") { + $feed.= " <rating>".FeedCreator::iTrunc(htmlspecialchars($this->rating),500)."</rating>\n"; + } + if ($this->skipHours!="") { + $feed.= " <skipHours>".htmlspecialchars($this->skipHours)."</skipHours>\n"; + } + if ($this->skipDays!="") { + $feed.= " <skipDays>".htmlspecialchars($this->skipDays)."</skipDays>\n"; + } + $feed.= $this->_createAdditionalElements($this->additionalElements, " "); + + for ($i=0;$i<count($this->items);$i++) { + $feed.= " <item>\n"; + $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n"; + $feed.= " <link>".htmlspecialchars($this->items[$i]->link)."</link>\n"; + $feed.= " <description>".$this->items[$i]->getDescription()."</description>\n"; + + if ($this->items[$i]->author!="") { + $feed.= " <author>".htmlspecialchars($this->items[$i]->author)."</author>\n"; + } + /* + // on hold + if ($this->items[$i]->source!="") { + $feed.= " <source>".htmlspecialchars($this->items[$i]->source)."</source>\n"; + } + */ + if ($this->items[$i]->category!="") { + $feed.= " <category>".htmlspecialchars($this->items[$i]->category)."</category>\n"; + } + if ($this->items[$i]->comments!="") { + $feed.= " <comments>".htmlspecialchars($this->items[$i]->comments)."</comments>\n"; + } + if ($this->items[$i]->date!="") { + $itemDate = new FeedDate($this->items[$i]->date); + $feed.= " <pubDate>".htmlspecialchars($itemDate->rfc822())."</pubDate>\n"; + } + if ($this->items[$i]->guid!="") { + $feed.= " <guid isPermaLink=\"false\">".htmlspecialchars($this->items[$i]->guid)."</guid>\n"; + } + $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); + $feed.= " </item>\n"; + } + $feed.= " </channel>\n"; + $feed.= "</rss>\n"; + return $feed; + } +} + + + +/** + * RSSCreator20 is a FeedCreator that implements RDF Site Summary (RSS) 2.0. + * + * @see http://backend.userland.com/rss + * @since 1.3 + * @author Kai Blankenhorn <kaib@bitfolge.de> + */ +class RSSCreator20 extends RSSCreator091 { + + function RSSCreator20() { + parent::_setRSSVersion("2.0"); + } + +} + + +/** + * PIECreator01 is a FeedCreator that implements the emerging PIE specification, + * as in http://intertwingly.net/wiki/pie/Syntax. + * + * @deprecated + * @since 1.3 + * @author Scott Reynen <scott@randomchaos.com> and Kai Blankenhorn <kaib@bitfolge.de> + */ +class PIECreator01 extends FeedCreator { + + function PIECreator01() { + $this->encoding = "utf-8"; + } + + function createFeed() { + $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n"; + $feed.= $this->_createStylesheetReferences(); + $feed.= "<feed version=\"0.1\" xmlns=\"http://example.com/newformat#\">\n"; + $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</title>\n"; + $this->truncSize = 500; + $feed.= " <subtitle>".$this->getDescription()."</subtitle>\n"; + $feed.= " <link>".$this->link."</link>\n"; + for ($i=0;$i<count($this->items);$i++) { + $feed.= " <entry>\n"; + $feed.= " <title>".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100)."</title>\n"; + $feed.= " <link>".htmlspecialchars($this->items[$i]->link)."</link>\n"; + $itemDate = new FeedDate($this->items[$i]->date); + $feed.= " <created>".htmlspecialchars($itemDate->iso8601())."</created>\n"; + $feed.= " <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n"; + $feed.= " <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n"; + $feed.= " <id>".htmlspecialchars($this->items[$i]->guid)."</id>\n"; + if ($this->items[$i]->author!="") { + $feed.= " <author>\n"; + $feed.= " <name>".htmlspecialchars($this->items[$i]->author)."</name>\n"; + if ($this->items[$i]->authorEmail!="") { + $feed.= " <email>".$this->items[$i]->authorEmail."</email>\n"; + } + $feed.=" </author>\n"; + } + $feed.= " <content type=\"text/html\" xml:lang=\"en-us\">\n"; + $feed.= " <div xmlns=\"http://www.w3.org/1999/xhtml\">".$this->items[$i]->getDescription()."</div>\n"; + $feed.= " </content>\n"; + $feed.= " </entry>\n"; + } + $feed.= "</feed>\n"; + return $feed; + } +} + + +/** + * AtomCreator03 is a FeedCreator that implements the atom specification, + * as in http://www.intertwingly.net/wiki/pie/FrontPage. + * Please note that just by using AtomCreator03 you won't automatically + * produce valid atom files. For example, you have to specify either an editor + * for the feed or an author for every single feed item. + * + * Some elements have not been implemented yet. These are (incomplete list): + * author URL, item author's email and URL, item contents, alternate links, + * other link content types than text/html. Some of them may be created with + * AtomCreator03::additionalElements. + * + * @see FeedCreator#additionalElements + * @since 1.6 + * @author Kai Blankenhorn <kaib@bitfolge.de>, Scott Reynen <scott@randomchaos.com> + */ +class AtomCreator03 extends FeedCreator { + + function AtomCreator03() { + $this->contentType = "application/atom+xml"; + $this->encoding = "utf-8"; + } + + function createFeed() { + $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n"; + $feed.= $this->_createGeneratorComment(); + $feed.= $this->_createStylesheetReferences(); + $feed.= "<feed version=\"0.3\" xmlns=\"http://purl.org/atom/ns#\""; + if ($this->language!="") { + $feed.= " xml:lang=\"".$this->language."\""; + } + $feed.= ">\n"; + $feed.= " <title>".htmlspecialchars($this->title)."</title>\n"; + $feed.= " <tagline>".htmlspecialchars($this->description)."</tagline>\n"; + $feed.= " <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->link)."\"/>\n"; + $feed.= " <id>".htmlspecialchars($this->link)."</id>\n"; + $now = new FeedDate(); + $feed.= " <modified>".htmlspecialchars($now->iso8601())."</modified>\n"; + if ($this->editor!="") { + $feed.= " <author>\n"; + $feed.= " <name>".$this->editor."</name>\n"; + if ($this->editorEmail!="") { + $feed.= " <email>".$this->editorEmail."</email>\n"; + } + $feed.= " </author>\n"; + } + $feed.= " <generator>".FEEDCREATOR_VERSION."</generator>\n"; + $feed.= $this->_createAdditionalElements($this->additionalElements, " "); + for ($i=0;$i<count($this->items);$i++) { + $feed.= " <entry>\n"; + $feed.= " <title>".htmlspecialchars(strip_tags($this->items[$i]->title))."</title>\n"; + $feed.= " <link rel=\"alternate\" type=\"text/html\" href=\"".htmlspecialchars($this->items[$i]->link)."\"/>\n"; + if ($this->items[$i]->date=="") { + $this->items[$i]->date = time(); + } + $itemDate = new FeedDate($this->items[$i]->date); + $feed.= " <created>".htmlspecialchars($itemDate->iso8601())."</created>\n"; + $feed.= " <issued>".htmlspecialchars($itemDate->iso8601())."</issued>\n"; + $feed.= " <modified>".htmlspecialchars($itemDate->iso8601())."</modified>\n"; + $feed.= " <id>".htmlspecialchars($this->items[$i]->link)."</id>\n"; + $feed.= $this->_createAdditionalElements($this->items[$i]->additionalElements, " "); + if ($this->items[$i]->author!="") { + $feed.= " <author>\n"; + $feed.= " <name>".htmlspecialchars($this->items[$i]->author)."</name>\n"; + $feed.= " </author>\n"; + } + if ($this->items[$i]->description!="") { + $feed.= " <summary>".htmlspecialchars($this->items[$i]->description)."</summary>\n"; + } + $feed.= " </entry>\n"; + } + $feed.= "</feed>\n"; + return $feed; + } +} + + +/** + * MBOXCreator is a FeedCreator that implements the mbox format + * as described in http://www.qmail.org/man/man5/mbox.html + * + * @since 1.3 + * @author Kai Blankenhorn <kaib@bitfolge.de> + */ +class MBOXCreator extends FeedCreator { + + function MBOXCreator() { + $this->contentType = "text/plain"; + $this->encoding = "ISO-8859-15"; + } + + function qp_enc($input = "", $line_max = 76) { + $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'); + $lines = preg_split("/(?:\r\n|\r|\n)/", $input); + $eol = "\r\n"; + $escape = "="; + $output = ""; + while( list(, $line) = each($lines) ) { + //$line = rtrim($line); // remove trailing white space -> no =20\r\n necessary + $linlen = strlen($line); + $newline = ""; + for($i = 0; $i < $linlen; $i++) { + $c = substr($line, $i, 1); + $dec = ord($c); + if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only + $c = "=20"; + } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required + $h2 = floor($dec/16); $h1 = floor($dec%16); + $c = $escape.$hex["$h2"].$hex["$h1"]; + } + if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted + $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay + $newline = ""; + } + $newline .= $c; + } // end of for + $output .= $newline.$eol; + } + return trim($output); + } + + + /** + * Builds the MBOX contents. + * @return string the feed's complete text + */ + function createFeed() { + for ($i=0;$i<count($this->items);$i++) { + if ($this->items[$i]->author!="") { + $from = $this->items[$i]->author; + } else { + $from = $this->title; + } + $itemDate = new FeedDate($this->items[$i]->date); + $feed.= "From ".strtr(MBOXCreator::qp_enc($from)," ","_")." ".date("D M d H:i:s Y",$itemDate->unix())."\n"; + $feed.= "Content-Type: text/plain;\n"; + $feed.= " charset=\"".$this->encoding."\"\n"; + $feed.= "Content-Transfer-Encoding: quoted-printable\n"; + $feed.= "Content-Type: text/plain\n"; + $feed.= "From: \"".MBOXCreator::qp_enc($from)."\"\n"; + $feed.= "Date: ".$itemDate->rfc822()."\n"; + $feed.= "Subject: ".MBOXCreator::qp_enc(FeedCreator::iTrunc($this->items[$i]->title,100))."\n"; + $feed.= "\n"; + $body = chunk_split(MBOXCreator::qp_enc($this->items[$i]->description)); + $feed.= preg_replace("~\nFrom ([^\n]*)(\n?)~","\n>From $1$2\n",$body); + $feed.= "\n"; + $feed.= "\n"; + } + return $feed; + } + + /** + * Generate a filename for the feed cache file. Overridden from FeedCreator to prevent XML data types. + * @return string the feed cache filename + * @since 1.4 + * @access private + */ + function _generateFilename() { + $fileInfo = pathinfo($_SERVER["PHP_SELF"]); + return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".mbox"; + } +} + + +/** + * OPMLCreator is a FeedCreator that implements OPML 1.0. + * + * @see http://opml.scripting.com/spec + * @author Dirk Clemens, Kai Blankenhorn + * @since 1.5 + */ +class OPMLCreator extends FeedCreator { + + function OPMLCreator() { + $this->encoding = "utf-8"; + } + + function createFeed() { + $feed = "<?xml version=\"1.0\" encoding=\"".$this->encoding."\"?>\n"; + $feed.= $this->_createGeneratorComment(); + $feed.= $this->_createStylesheetReferences(); + $feed.= "<opml xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n"; + $feed.= " <head>\n"; + $feed.= " <title>".htmlspecialchars($this->title)."</title>\n"; + if ($this->pubDate!="") { + $date = new FeedDate($this->pubDate); + $feed.= " <dateCreated>".$date->rfc822()."</dateCreated>\n"; + } + if ($this->lastBuildDate!="") { + $date = new FeedDate($this->lastBuildDate); + $feed.= " <dateModified>".$date->rfc822()."</dateModified>\n"; + } + if ($this->editor!="") { + $feed.= " <ownerName>".$this->editor."</ownerName>\n"; + } + if ($this->editorEmail!="") { + $feed.= " <ownerEmail>".$this->editorEmail."</ownerEmail>\n"; + } + $feed.= " </head>\n"; + $feed.= " <body>\n"; + for ($i=0;$i<count($this->items);$i++) { + $feed.= " <outline type=\"rss\" "; + $title = htmlspecialchars(strip_tags(strtr($this->items[$i]->title,"\n\r"," "))); + $feed.= " title=\"".$title."\""; + $feed.= " text=\"".$title."\""; + //$feed.= " description=\"".htmlspecialchars($this->items[$i]->description)."\""; + $feed.= " url=\"".htmlspecialchars($this->items[$i]->link)."\""; + $feed.= "/>\n"; + } + $feed.= " </body>\n"; + $feed.= "</opml>\n"; + return $feed; + } +} + + + +/** + * HTMLCreator is a FeedCreator that writes an HTML feed file to a specific + * location, overriding the createFeed method of the parent FeedCreator. + * The HTML produced can be included over http by scripting languages, or serve + * as the source for an IFrame. + * All output by this class is embedded in <div></div> tags to enable formatting + * using CSS. + * + * @author Pascal Van Hecke + * @since 1.7 + */ +class HTMLCreator extends FeedCreator { + + var $contentType = "text/html"; + + /** + * Contains HTML to be output at the start of the feed's html representation. + */ + var $header; + + /** + * Contains HTML to be output at the end of the feed's html representation. + */ + var $footer ; + + /** + * Contains HTML to be output between entries. A separator is only used in + * case of multiple entries. + */ + var $separator; + + /** + * Used to prefix the stylenames to make sure they are unique + * and do not clash with stylenames on the users' page. + */ + var $stylePrefix; + + /** + * Determines whether the links open in a new window or not. + */ + var $openInNewWindow = true; + + var $imageAlign ="right"; + + /** + * In case of very simple output you may want to get rid of the style tags, + * hence this variable. There's no equivalent on item level, but of course you can + * add strings to it while iterating over the items ($this->stylelessOutput .= ...) + * and when it is non-empty, ONLY the styleless output is printed, the rest is ignored + * in the function createFeed(). + */ + var $stylelessOutput =""; + + /** + * Writes the HTML. + * @return string the scripts's complete text + */ + function createFeed() { + // if there is styleless output, use the content of this variable and ignore the rest + if ($this->stylelessOutput!="") { + return $this->stylelessOutput; + } + + //if no stylePrefix is set, generate it yourself depending on the script name + if ($this->stylePrefix=="") { + $this->stylePrefix = str_replace(".", "_", $this->_generateFilename())."_"; + } + + //set an openInNewWindow_token_to be inserted or not + if ($this->openInNewWindow) { + $targetInsert = " target='_blank'"; + } + + // use this array to put the lines in and implode later with "document.write" javascript + $feedArray = array(); + if ($this->image!=null) { + $imageStr = "<a href='".$this->image->link."'".$targetInsert.">". + "<img src='".$this->image->url."' border='0' alt='". + FeedCreator::iTrunc(htmlspecialchars($this->image->title),100). + "' align='".$this->imageAlign."' "; + if ($this->image->width) { + $imageStr .=" width='".$this->image->width. "' "; + } + if ($this->image->height) { + $imageStr .=" height='".$this->image->height."' "; + } + $imageStr .="/></a>"; + $feedArray[] = $imageStr; + } + + if ($this->title) { + $feedArray[] = "<div class='".$this->stylePrefix."title'><a href='".$this->link."' ".$targetInsert." class='".$this->stylePrefix."title'>". + FeedCreator::iTrunc(htmlspecialchars($this->title),100)."</a></div>"; + } + if ($this->getDescription()) { + $feedArray[] = "<div class='".$this->stylePrefix."description'>". + str_replace("]]>", "", str_replace("<![CDATA[", "", $this->getDescription())). + "</div>"; + } + + if ($this->header) { + $feedArray[] = "<div class='".$this->stylePrefix."header'>".$this->header."</div>"; + } + + for ($i=0;$i<count($this->items);$i++) { + if ($this->separator and $i > 0) { + $feedArray[] = "<div class='".$this->stylePrefix."separator'>".$this->separator."</div>"; + } + + if ($this->items[$i]->title) { + if ($this->items[$i]->link) { + $feedArray[] = + "<div class='".$this->stylePrefix."item_title'><a href='".$this->items[$i]->link."' class='".$this->stylePrefix. + "item_title'".$targetInsert.">".FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100). + "</a></div>"; + } else { + $feedArray[] = + "<div class='".$this->stylePrefix."item_title'>". + FeedCreator::iTrunc(htmlspecialchars(strip_tags($this->items[$i]->title)),100). + "</div>"; + } + } + if ($this->items[$i]->getDescription()) { + $feedArray[] = + "<div class='".$this->stylePrefix."item_description'>". + str_replace("]]>", "", str_replace("<![CDATA[", "", $this->items[$i]->getDescription())). + "</div>"; + } + } + if ($this->footer) { + $feedArray[] = "<div class='".$this->stylePrefix."footer'>".$this->footer."</div>"; + } + + $feed= "".join($feedArray, "\r\n"); + return $feed; + } + + /** + * Overrrides parent to produce .html extensions + * + * @return string the feed cache filename + * @since 1.4 + * @access private + */ + function _generateFilename() { + $fileInfo = pathinfo($_SERVER["PHP_SELF"]); + return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".html"; + } +} + + +/** + * JSCreator is a class that writes a js file to a specific + * location, overriding the createFeed method of the parent HTMLCreator. + * + * @author Pascal Van Hecke + */ +class JSCreator extends HTMLCreator { + var $contentType = "text/javascript"; + + /** + * writes the javascript + * @return string the scripts's complete text + */ + function createFeed() + { + $feed = parent::createFeed(); + $feedArray = explode("\n",$feed); + + $jsFeed = ""; + foreach ($feedArray as $value) { + $jsFeed .= "document.write('".trim(addslashes($value))."');\n"; + } + return $jsFeed; + } + + /** + * Overrrides parent to produce .js extensions + * + * @return string the feed cache filename + * @since 1.4 + * @access private + */ + function _generateFilename() { + $fileInfo = pathinfo($_SERVER["PHP_SELF"]); + return substr($fileInfo["basename"],0,-(strlen($fileInfo["extension"])+1)).".js"; + } + +} + + + +/*** TEST SCRIPT ********************************************************* + +//include("feedcreator.class.php"); + +$rss = new UniversalFeedCreator(); +$rss->useCached(); +$rss->title = "PHP news"; +$rss->description = "daily news from the PHP scripting world"; + +//optional +//$rss->descriptionTruncSize = 500; +//$rss->descriptionHtmlSyndicated = true; +//$rss->xslStyleSheet = "http://feedster.com/rss20.xsl"; + +$rss->link = "http://www.dailyphp.net/news"; +$rss->feedURL = "http://www.dailyphp.net/".$PHP_SELF; + +$image = new FeedImage(); +$image->title = "dailyphp.net logo"; +$image->url = "http://www.dailyphp.net/images/logo.gif"; +$image->link = "http://www.dailyphp.net"; +$image->description = "Feed provided by dailyphp.net. Click to visit."; + +//optional +$image->descriptionTruncSize = 500; +$image->descriptionHtmlSyndicated = true; + +$rss->image = $image; + +// get your news items from somewhere, e.g. your database: +//mysql_select_db($dbHost, $dbUser, $dbPass); +//$res = mysql_query("SELECT * FROM news ORDER BY newsdate DESC"); +//while ($data = mysql_fetch_object($res)) { + $item = new FeedItem(); + $item->title = "This is an the test title of an item"; + $item->link = "http://localhost/item/"; + $item->description = "<b>description in </b><br/>HTML"; + + //optional + //item->descriptionTruncSize = 500; + $item->descriptionHtmlSyndicated = true; + + $item->date = time(); + $item->source = "http://www.dailyphp.net"; + $item->author = "John Doe"; + + $rss->addItem($item); +//} + +// valid format strings are: RSS0.91, RSS1.0, RSS2.0, PIE0.1, MBOX, OPML, ATOM0.3, HTML, JS +echo $rss->saveFeed("RSS0.91", "feed.xml"); + + + +***************************************************************************/ + +?> diff --git a/BSF/include/filter.inc.php b/BSF/include/filter.inc.php new file mode 100644 index 000000000..b77ddca98 --- /dev/null +++ b/BSF/include/filter.inc.php @@ -0,0 +1,141 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// $filter['enabled']: Filter is enabled +// $filter['check_key']: Check key to valitade computed filter data +// $filter['recent_period']: Recent period used to computed filter data +// $filter['categories']: Computed data of filtered categories +// $filter['visible_categories']: +// List of visible categories (count(visible) < count(forbidden) more often) +// $filter['visible_images']: List of visible images + +if (!get_filter_page_value('cancel')) +{ + if (isset($_GET['filter'])) + { + $filter['matches'] = array(); + $filter['enabled'] = + preg_match('/^start-recent-(\d+)$/', $_GET['filter'], $filter['matches']) === 1; + } + else + { + $filter['enabled'] = pwg_get_session_var('filter_enabled', false); + } +} +else +{ + $filter['enabled'] = false; +} + +if ($filter['enabled']) +{ + if (isset($filter['matches'])) + { + $filter['recent_period'] = $filter['matches'][1]; + } + else + { + $filter['recent_period'] = pwg_get_session_var('filter_recent_period', $user['recent_period']); + } + + if ( + // New filter + !pwg_get_session_var('filter_enabled', false) or + // Cache data updated + $user['need_update_done'] or + // Date, period, user are changed + (pwg_get_session_var('filter_check_key', '') != get_filter_check_key()) + ) + { + // Need to compute dats + $filter['check_key'] = get_filter_check_key(); + $filter['categories'] = get_computed_categories($user, (int)$filter['recent_period']); + + $filter['visible_categories'] = implode(',', array_keys($filter['categories'])); + if (empty($filter['visible_categories'])) + { + // Must be not empty + $filter['visible_categories'] = -1; + } + + $query =' +SELECT + distinct image_id +FROM '. + IMAGE_CATEGORY_TABLE.' INNER JOIN '.IMAGES_TABLE.' ON image_id = id +WHERE '; + if (!empty($filter['visible_categories'])) + { + $query.= ' + category_id IN ('.$filter['visible_categories'].') and'; + } + $query.= ' + date_available >= SUBDATE( + CURRENT_DATE,INTERVAL '.$filter['recent_period'].' DAY)'; + + $filter['visible_images'] = implode(',', array_from_query($query, 'image_id')); + + if (empty($filter['visible_images'])) + { + // Must be not empty + $filter['visible_images'] = -1; + } + + // Save filter data on session + pwg_set_session_var('filter_enabled', $filter['enabled']); + pwg_set_session_var('filter_check_key', $filter['check_key']); + pwg_set_session_var('filter_recent_period', $filter['recent_period']); + pwg_set_session_var('filter_categories', serialize($filter['categories'])); + pwg_set_session_var('filter_visible_categories', $filter['visible_categories']); + pwg_set_session_var('filter_visible_images', $filter['visible_images']); + + } + else + { + // Read only data + $filter['check_key'] = pwg_get_session_var('filter_check_key', ''); + $filter['categories'] = unserialize(pwg_get_session_var('filter_categories', serialize(array()))); + $filter['visible_categories'] = pwg_get_session_var('filter_visible_categories', ''); + $filter['visible_images'] = pwg_get_session_var('filter_visible_images', ''); + } + + if (get_filter_page_value('add_notes')) + { + $header_notes[] = l10n_dec('note_filter_day', 'note_filter_days', $filter['recent_period']); + } +} +else +{ + if (pwg_get_session_var('filter_enabled', false)) + { + pwg_unset_session_var('filter_enabled'); + pwg_unset_session_var('filter_check_key'); + pwg_unset_session_var('filter_recent_period'); + pwg_unset_session_var('filter_categories'); + pwg_unset_session_var('filter_visible_categories'); + pwg_unset_session_var('filter_visible_images'); + } +} + + +?> diff --git a/BSF/include/functions.inc.php b/BSF/include/functions.inc.php new file mode 100644 index 000000000..a1b589999 --- /dev/null +++ b/BSF/include/functions.inc.php @@ -0,0 +1,1557 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +include_once( PHPWG_ROOT_PATH .'include/functions_user.inc.php' ); +include_once( PHPWG_ROOT_PATH .'include/functions_cookie.inc.php' ); +include_once( PHPWG_ROOT_PATH .'include/functions_session.inc.php' ); +include_once( PHPWG_ROOT_PATH .'include/functions_category.inc.php' ); +include_once( PHPWG_ROOT_PATH .'include/functions_xml.inc.php' ); +include_once( PHPWG_ROOT_PATH .'include/functions_group.inc.php' ); +include_once( PHPWG_ROOT_PATH .'include/functions_html.inc.php' ); +include_once( PHPWG_ROOT_PATH .'include/functions_tag.inc.php' ); +include_once( PHPWG_ROOT_PATH .'include/functions_url.inc.php' ); +include_once( PHPWG_ROOT_PATH .'include/functions_plugins.inc.php' ); + +//----------------------------------------------------------- generic functions + +/** + * returns an array containing the possible values of an enum field + * + * @param string tablename + * @param string fieldname + */ +function get_enums($table, $field) +{ + // retrieving the properties of the table. Each line represents a field : + // columns are 'Field', 'Type' + $result = pwg_query('desc '.$table); + while ($row = mysql_fetch_array($result)) + { + // we are only interested in the the field given in parameter for the + // function + if ($row['Field'] == $field) + { + // retrieving possible values of the enum field + // enum('blue','green','black') + $options = explode(',', substr($row['Type'], 5, -1)); + foreach ($options as $i => $option) + { + $options[$i] = str_replace("'", '',$option); + } + } + } + mysql_free_result($result); + return $options; +} + +// get_boolean transforms a string to a boolean value. If the string is +// "false" (case insensitive), then the boolean value false is returned. In +// any other case, true is returned. +function get_boolean( $string ) +{ + $boolean = true; + if ( preg_match( '/^false$/i', $string ) ) + { + $boolean = false; + } + return $boolean; +} + +/** + * returns boolean string 'true' or 'false' if the given var is boolean + * + * @param mixed $var + * @return mixed + */ +function boolean_to_string($var) +{ + if (is_bool($var)) + { + if ($var) + { + return 'true'; + } + else + { + return 'false'; + } + } + else + { + return $var; + } +} + +// The function get_moment returns a float value coresponding to the number +// of seconds since the unix epoch (1st January 1970) and the microseconds +// are precised : e.g. 1052343429.89276600 +function get_moment() +{ + $t1 = explode( ' ', microtime() ); + $t2 = explode( '.', $t1[0] ); + $t2 = $t1[1].'.'.$t2[1]; + return $t2; +} + +// The function get_elapsed_time returns the number of seconds (with 3 +// decimals precision) between the start time and the end time given. +function get_elapsed_time( $start, $end ) +{ + return number_format( $end - $start, 3, '.', ' ').' s'; +} + +// - The replace_space function replaces space and '-' characters +// by their HTML equivalent &nbsb; and − +// - The function does not replace characters in HTML tags +// - This function was created because IE5 does not respect the +// CSS "white-space: nowrap;" property unless space and minus +// characters are replaced like this function does. +// - Example : +// <div class="foo">My friend</div> +// ( 01234567891111111111222222222233 ) +// ( 0123456789012345678901 ) +// becomes : +// <div class="foo">My friend</div> +function replace_space( $string ) +{ + //return $string; + $return_string = ''; + // $remaining is the rest of the string where to replace spaces characters + $remaining = $string; + // $start represents the position of the next '<' character + // $end represents the position of the next '>' character + $start = 0; + $end = 0; + $start = strpos ( $remaining, '<' ); // -> 0 + $end = strpos ( $remaining, '>' ); // -> 16 + // as long as a '<' and his friend '>' are found, we loop + while ( is_numeric( $start ) and is_numeric( $end ) ) + { + // $treatment is the part of the string to treat + // In the first loop of our example, this variable is empty, but in the + // second loop, it equals 'My friend' + $treatment = substr ( $remaining, 0, $start ); + // Replacement of ' ' by his equivalent ' ' + $treatment = str_replace( ' ', ' ', $treatment ); + $treatment = str_replace( '-', '−', $treatment ); + // composing the string to return by adding the treated string and the + // following HTML tag -> 'My friend</div>' + $return_string.= $treatment.substr( $remaining, $start, $end-$start+1 ); + // the remaining string is deplaced to the part after the '>' of this + // loop + $remaining = substr ( $remaining, $end + 1, strlen( $remaining ) ); + $start = strpos ( $remaining, '<' ); + $end = strpos ( $remaining, '>' ); + } + $treatment = str_replace( ' ', ' ', $remaining ); + $treatment = str_replace( '-', '−', $treatment ); + $return_string.= $treatment; + + return $return_string; +} + +// get_extension returns the part of the string after the last "." +function get_extension( $filename ) +{ + return substr( strrchr( $filename, '.' ), 1, strlen ( $filename ) ); +} + +// get_filename_wo_extension returns the part of the string before the last +// ".". +// get_filename_wo_extension( 'test.tar.gz' ) -> 'test.tar' +function get_filename_wo_extension( $filename ) +{ + $pos = strrpos( $filename, '.' ); + return ($pos===false) ? $filename : substr( $filename, 0, $pos); +} + +/** + * returns an array contening sub-directories, excluding "CVS" + * + * @param string $dir + * @return array + */ +function get_dirs($directory) +{ + $sub_dirs = array(); + + if ($opendir = opendir($directory)) + { + while ($file = readdir($opendir)) + { + if ($file != '.' + and $file != '..' + and is_dir($directory.'/'.$file) + and $file != 'CVS' + and $file != '.svn') + { + array_push($sub_dirs, $file); + } + } + } + return $sub_dirs; +} + +/** + * returns thumbnail directory name of input diretoty name + * make thumbnail directory is necessary + * set error messages on array messages + * + * @param: + * string $dirname + * arrayy $errors + * @return bool false on error else string directory name + */ +function mkget_thumbnail_dir($dirname, &$errors) +{ + $tndir = $dirname.'/thumbnail'; + if (!is_dir($tndir)) + { + if (!is_writable($dirname)) + { + array_push($errors, + '['.$dirname.'] : '.l10n('no_write_access')); + return false; + } + umask(0000); + mkdir($tndir, 0777); + } + + return $tndir; +} + +// The get_picture_size function return an array containing : +// - $picture_size[0] : final width +// - $picture_size[1] : final height +// The final dimensions are calculated thanks to the original dimensions and +// the maximum dimensions given in parameters. get_picture_size respects +// the width/height ratio +function get_picture_size( $original_width, $original_height, + $max_width, $max_height ) +{ + $width = $original_width; + $height = $original_height; + $is_original_size = true; + + if ( $max_width != "" ) + { + if ( $original_width > $max_width ) + { + $width = $max_width; + $height = floor( ( $width * $original_height ) / $original_width ); + } + } + if ( $max_height != "" ) + { + if ( $original_height > $max_height ) + { + $height = $max_height; + $width = floor( ( $height * $original_width ) / $original_height ); + $is_original_size = false; + } + } + if ( is_numeric( $max_width ) and is_numeric( $max_height ) + and $max_width != 0 and $max_height != 0 ) + { + $ratioWidth = $original_width / $max_width; + $ratioHeight = $original_height / $max_height; + if ( ( $ratioWidth > 1 ) or ( $ratioHeight > 1 ) ) + { + if ( $ratioWidth < $ratioHeight ) + { + $width = floor( $original_width / $ratioHeight ); + $height = $max_height; + } + else + { + $width = $max_width; + $height = floor( $original_height / $ratioWidth ); + } + $is_original_size = false; + } + } + $picture_size = array(); + $picture_size[0] = $width; + $picture_size[1] = $height; + return $picture_size; +} + +/* Returns true if the string appears to be encoded in UTF-8. (from wordpress) + * @param string Str + */ +function seems_utf8($Str) { # by bmorel at ssi dot fr + for ($i=0; $i<strlen($Str); $i++) { + if (ord($Str[$i]) < 0x80) continue; # 0bbbbbbb + elseif ((ord($Str[$i]) & 0xE0) == 0xC0) $n=1; # 110bbbbb + elseif ((ord($Str[$i]) & 0xF0) == 0xE0) $n=2; # 1110bbbb + elseif ((ord($Str[$i]) & 0xF8) == 0xF0) $n=3; # 11110bbb + elseif ((ord($Str[$i]) & 0xFC) == 0xF8) $n=4; # 111110bb + elseif ((ord($Str[$i]) & 0xFE) == 0xFC) $n=5; # 1111110b + else return false; # Does not match any model + for ($j=0; $j<$n; $j++) { # n bytes matching 10bbbbbb follow ? + if ((++$i == strlen($Str)) || ((ord($Str[$i]) & 0xC0) != 0x80)) + return false; + } + } + return true; +} + +/* Remove accents from a UTF-8 or ISO-859-1 string (from wordpress) + * @param string sstring - an UTF-8 or ISO-8859-1 string + */ +function remove_accents($string) +{ + if ( !preg_match('/[\x80-\xff]/', $string) ) + return $string; + + if (seems_utf8($string)) { + $chars = array( + // Decompositions for Latin-1 Supplement + chr(195).chr(128) => 'A', chr(195).chr(129) => 'A', + chr(195).chr(130) => 'A', chr(195).chr(131) => 'A', + chr(195).chr(132) => 'A', chr(195).chr(133) => 'A', + chr(195).chr(135) => 'C', chr(195).chr(136) => 'E', + chr(195).chr(137) => 'E', chr(195).chr(138) => 'E', + chr(195).chr(139) => 'E', chr(195).chr(140) => 'I', + chr(195).chr(141) => 'I', chr(195).chr(142) => 'I', + chr(195).chr(143) => 'I', chr(195).chr(145) => 'N', + chr(195).chr(146) => 'O', chr(195).chr(147) => 'O', + chr(195).chr(148) => 'O', chr(195).chr(149) => 'O', + chr(195).chr(150) => 'O', chr(195).chr(153) => 'U', + chr(195).chr(154) => 'U', chr(195).chr(155) => 'U', + chr(195).chr(156) => 'U', chr(195).chr(157) => 'Y', + chr(195).chr(159) => 's', chr(195).chr(160) => 'a', + chr(195).chr(161) => 'a', chr(195).chr(162) => 'a', + chr(195).chr(163) => 'a', chr(195).chr(164) => 'a', + chr(195).chr(165) => 'a', chr(195).chr(167) => 'c', + chr(195).chr(168) => 'e', chr(195).chr(169) => 'e', + chr(195).chr(170) => 'e', chr(195).chr(171) => 'e', + chr(195).chr(172) => 'i', chr(195).chr(173) => 'i', + chr(195).chr(174) => 'i', chr(195).chr(175) => 'i', + chr(195).chr(177) => 'n', chr(195).chr(178) => 'o', + chr(195).chr(179) => 'o', chr(195).chr(180) => 'o', + chr(195).chr(181) => 'o', chr(195).chr(182) => 'o', + chr(195).chr(182) => 'o', chr(195).chr(185) => 'u', + chr(195).chr(186) => 'u', chr(195).chr(187) => 'u', + chr(195).chr(188) => 'u', chr(195).chr(189) => 'y', + chr(195).chr(191) => 'y', + // Decompositions for Latin Extended-A + chr(196).chr(128) => 'A', chr(196).chr(129) => 'a', + chr(196).chr(130) => 'A', chr(196).chr(131) => 'a', + chr(196).chr(132) => 'A', chr(196).chr(133) => 'a', + chr(196).chr(134) => 'C', chr(196).chr(135) => 'c', + chr(196).chr(136) => 'C', chr(196).chr(137) => 'c', + chr(196).chr(138) => 'C', chr(196).chr(139) => 'c', + chr(196).chr(140) => 'C', chr(196).chr(141) => 'c', + chr(196).chr(142) => 'D', chr(196).chr(143) => 'd', + chr(196).chr(144) => 'D', chr(196).chr(145) => 'd', + chr(196).chr(146) => 'E', chr(196).chr(147) => 'e', + chr(196).chr(148) => 'E', chr(196).chr(149) => 'e', + chr(196).chr(150) => 'E', chr(196).chr(151) => 'e', + chr(196).chr(152) => 'E', chr(196).chr(153) => 'e', + chr(196).chr(154) => 'E', chr(196).chr(155) => 'e', + chr(196).chr(156) => 'G', chr(196).chr(157) => 'g', + chr(196).chr(158) => 'G', chr(196).chr(159) => 'g', + chr(196).chr(160) => 'G', chr(196).chr(161) => 'g', + chr(196).chr(162) => 'G', chr(196).chr(163) => 'g', + chr(196).chr(164) => 'H', chr(196).chr(165) => 'h', + chr(196).chr(166) => 'H', chr(196).chr(167) => 'h', + chr(196).chr(168) => 'I', chr(196).chr(169) => 'i', + chr(196).chr(170) => 'I', chr(196).chr(171) => 'i', + chr(196).chr(172) => 'I', chr(196).chr(173) => 'i', + chr(196).chr(174) => 'I', chr(196).chr(175) => 'i', + chr(196).chr(176) => 'I', chr(196).chr(177) => 'i', + chr(196).chr(178) => 'IJ',chr(196).chr(179) => 'ij', + chr(196).chr(180) => 'J', chr(196).chr(181) => 'j', + chr(196).chr(182) => 'K', chr(196).chr(183) => 'k', + chr(196).chr(184) => 'k', chr(196).chr(185) => 'L', + chr(196).chr(186) => 'l', chr(196).chr(187) => 'L', + chr(196).chr(188) => 'l', chr(196).chr(189) => 'L', + chr(196).chr(190) => 'l', chr(196).chr(191) => 'L', + chr(197).chr(128) => 'l', chr(197).chr(129) => 'L', + chr(197).chr(130) => 'l', chr(197).chr(131) => 'N', + chr(197).chr(132) => 'n', chr(197).chr(133) => 'N', + chr(197).chr(134) => 'n', chr(197).chr(135) => 'N', + chr(197).chr(136) => 'n', chr(197).chr(137) => 'N', + chr(197).chr(138) => 'n', chr(197).chr(139) => 'N', + chr(197).chr(140) => 'O', chr(197).chr(141) => 'o', + chr(197).chr(142) => 'O', chr(197).chr(143) => 'o', + chr(197).chr(144) => 'O', chr(197).chr(145) => 'o', + chr(197).chr(146) => 'OE',chr(197).chr(147) => 'oe', + chr(197).chr(148) => 'R',chr(197).chr(149) => 'r', + chr(197).chr(150) => 'R',chr(197).chr(151) => 'r', + chr(197).chr(152) => 'R',chr(197).chr(153) => 'r', + chr(197).chr(154) => 'S',chr(197).chr(155) => 's', + chr(197).chr(156) => 'S',chr(197).chr(157) => 's', + chr(197).chr(158) => 'S',chr(197).chr(159) => 's', + chr(197).chr(160) => 'S', chr(197).chr(161) => 's', + chr(197).chr(162) => 'T', chr(197).chr(163) => 't', + chr(197).chr(164) => 'T', chr(197).chr(165) => 't', + chr(197).chr(166) => 'T', chr(197).chr(167) => 't', + chr(197).chr(168) => 'U', chr(197).chr(169) => 'u', + chr(197).chr(170) => 'U', chr(197).chr(171) => 'u', + chr(197).chr(172) => 'U', chr(197).chr(173) => 'u', + chr(197).chr(174) => 'U', chr(197).chr(175) => 'u', + chr(197).chr(176) => 'U', chr(197).chr(177) => 'u', + chr(197).chr(178) => 'U', chr(197).chr(179) => 'u', + chr(197).chr(180) => 'W', chr(197).chr(181) => 'w', + chr(197).chr(182) => 'Y', chr(197).chr(183) => 'y', + chr(197).chr(184) => 'Y', chr(197).chr(185) => 'Z', + chr(197).chr(186) => 'z', chr(197).chr(187) => 'Z', + chr(197).chr(188) => 'z', chr(197).chr(189) => 'Z', + chr(197).chr(190) => 'z', chr(197).chr(191) => 's', + // Euro Sign + chr(226).chr(130).chr(172) => 'E', + // GBP (Pound) Sign + chr(194).chr(163) => ''); + + $string = strtr($string, $chars); + } else { + // Assume ISO-8859-1 if not UTF-8 + $chars['in'] = chr(128).chr(131).chr(138).chr(142).chr(154).chr(158) + .chr(159).chr(162).chr(165).chr(181).chr(192).chr(193).chr(194) + .chr(195).chr(196).chr(197).chr(199).chr(200).chr(201).chr(202) + .chr(203).chr(204).chr(205).chr(206).chr(207).chr(209).chr(210) + .chr(211).chr(212).chr(213).chr(214).chr(216).chr(217).chr(218) + .chr(219).chr(220).chr(221).chr(224).chr(225).chr(226).chr(227) + .chr(228).chr(229).chr(231).chr(232).chr(233).chr(234).chr(235) + .chr(236).chr(237).chr(238).chr(239).chr(241).chr(242).chr(243) + .chr(244).chr(245).chr(246).chr(248).chr(249).chr(250).chr(251) + .chr(252).chr(253).chr(255); + + $chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy"; + + $string = strtr($string, $chars['in'], $chars['out']); + $double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254)); + $double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th'); + $string = str_replace($double_chars['in'], $double_chars['out'], $string); + } + + return $string; +} + +/** + * simplify a string to insert it into an URL + * + * @param string + * @return string + */ +function str2url($str) +{ + $str = remove_accents($str); + $str = preg_replace('/[^a-z0-9_\s\'\:\/\[\],-]/','',strtolower($str)); + $str = preg_replace('/[\s\'\:\/\[\],-]+/',' ',trim($str)); + $res = str_replace(' ','_',$str); + + return $res; +} + +//-------------------------------------------- Piwigo specific functions + +/** + * returns an array with a list of {language_code => language_name} + * + * @returns array + */ +function get_languages($target_charset = null) +{ + if ( empty($target_charset) ) + { + $target_charset = get_pwg_charset(); + } + $target_charset = strtolower($target_charset); + + $dir = opendir(PHPWG_ROOT_PATH.'language'); + $languages = array(); + + while ($file = readdir($dir)) + { + $path = PHPWG_ROOT_PATH.'language/'.$file; + if (is_dir($path) and !is_link($path) and file_exists($path.'/iso.txt')) + { + list($language_name) = @file($path.'/iso.txt'); + + $langdef = explode('.',$file); + if (count($langdef)>1) // (langCode,encoding) + { + $langdef[1] = strtolower($langdef[1]); + + if ( + $target_charset==$langdef[1] + or + ($target_charset=='utf-8' and $langdef[1]=='iso-8859-1') + or + ($target_charset=='iso-8859-1' and + in_array( substr($langdef[0],2), array('en','fr','de','es','it','nl'))) + ) + { + $language_name = convert_charset($language_name, + $langdef[1], $target_charset); + $languages[ $langdef[0] ] = $language_name; + } + else + continue; // the language encoding is not compatible with our charset + } + else + { // UTF-8 + $language_name = convert_charset($language_name, + 'utf-8', $target_charset); + $languages[$file] = $language_name; + } + } + } + closedir($dir); + @asort($languages); + @reset($languages); + + return $languages; +} + +function pwg_log($image_id = null, $image_type = null) +{ + global $conf, $user, $page; + + $do_log = true; + if (!$conf['log']) + { + $do_log = false; + } + if (is_admin() and !$conf['history_admin']) + { + $do_log = false; + } + if (is_a_guest() and !$conf['history_guest']) + { + $do_log = false; + } + + $do_log = trigger_event('pwg_log_allowed', $do_log, $image_id, $image_type); + + if (!$do_log) + { + return false; + } + + $tags_string = null; + if (isset($page['section']) and $page['section'] == 'tags') + { + $tag_ids = array(); + foreach ($page['tags'] as $tag) + { + array_push($tag_ids, $tag['id']); + } + + $tags_string = implode(',', $tag_ids); + } + + $query = ' +INSERT INTO '.HISTORY_TABLE.' + ( + date, + time, + user_id, + IP, + section, + category_id, + image_id, + image_type, + tag_ids + ) + VALUES + ( + CURDATE(), + CURTIME(), + '.$user['id'].', + \''.$_SERVER['REMOTE_ADDR'].'\', + '.(isset($page['section']) ? "'".$page['section']."'" : 'NULL').', + '.(isset($page['category']['id']) ? $page['category']['id'] : 'NULL').', + '.(isset($image_id) ? $image_id : 'NULL').', + '.(isset($image_type) ? "'".$image_type."'" : 'NULL').', + '.(isset($tags_string) ? "'".$tags_string."'" : 'NULL').' + ) +;'; + pwg_query($query); + + return true; +} + +// format_date returns a formatted date for display. The date given in +// argument can be a unixdate (number of seconds since the 01.01.1970) or an +// american format (2003-09-15). By option, you can show the time. The +// output is internationalized. +// +// format_date( "2003-09-15", 'us', true ) -> "Monday 15 September 2003 21:52" +function format_date($date, $type = 'us', $show_time = false) +{ + global $lang; + + list($year,$month,$day,$hour,$minute,$second) = array(0,0,0,0,0,0); + + switch ( $type ) + { + case 'us' : + { + list($year,$month,$day) = explode('-', $date); + break; + } + case 'unix' : + { + list($year,$month,$day,$hour,$minute) = + explode('.', date('Y.n.j.G.i', $date)); + break; + } + case 'mysql_datetime' : + { + preg_match('/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/', + $date, $out); + list($year,$month,$day,$hour,$minute,$second) = + array($out[1],$out[2],$out[3],$out[4],$out[5],$out[6]); + break; + } + } + $formated_date = ''; + // before 1970, Microsoft Windows can't mktime + if ($year >= 1970) + { + // we ask midday because Windows think it's prior to midnight with a + // zero and refuse to work + $formated_date.= $lang['day'][date('w', mktime(12,0,0,$month,$day,$year))]; + } + $formated_date.= ' '.$day; + $formated_date.= ' '.$lang['month'][(int)$month]; + $formated_date.= ' '.$year; + if ($show_time) + { + $formated_date.= ' '.$hour.':'.$minute; + } + + return $formated_date; +} + +function pwg_query($query) +{ + global $conf,$page,$debug,$t2; + + $start = get_moment(); + $result = mysql_query($query) or my_error($query."\n"); + + $time = get_moment() - $start; + + if (!isset($page['count_queries'])) + { + $page['count_queries'] = 0; + $page['queries_time'] = 0; + } + + $page['count_queries']++; + $page['queries_time']+= $time; + + if ($conf['show_queries']) + { + $output = ''; + $output.= '<pre>['.$page['count_queries'].'] '; + $output.= "\n".$query; + $output.= "\n".'(this query time : '; + $output.= '<b>'.number_format($time, 3, '.', ' ').' s)</b>'; + $output.= "\n".'(total SQL time : '; + $output.= number_format($page['queries_time'], 3, '.', ' ').' s)'; + $output.= "\n".'(total time : '; + $output.= number_format( ($time+$start-$t2), 3, '.', ' ').' s)'; + if ( $result!=null and preg_match('/\s*SELECT\s+/i',$query) ) + { + $output.= "\n".'(num rows : '; + $output.= mysql_num_rows($result).' )'; + } + elseif ( $result!=null + and preg_match('/\s*INSERT|UPDATE|REPLACE|DELETE\s+/i',$query) ) + { + $output.= "\n".'(affected rows : '; + $output.= mysql_affected_rows().' )'; + } + $output.= "</pre>\n"; + + $debug .= $output; + } + + return $result; +} + +function pwg_debug( $string ) +{ + global $debug,$t2,$page; + + $now = explode( ' ', microtime() ); + $now2 = explode( '.', $now[0] ); + $now2 = $now[1].'.'.$now2[1]; + $time = number_format( $now2 - $t2, 3, '.', ' ').' s'; + $debug .= '<p>'; + $debug.= '['.$time.', '; + $debug.= $page['count_queries'].' queries] : '.$string; + $debug.= "</p>\n"; +} + +/** + * Redirects to the given URL (HTTP method) + * + * Note : once this function called, the execution doesn't go further + * (presence of an exit() instruction. + * + * @param string $url + * @return void + */ +function redirect_http( $url ) +{ + if (ob_get_length () !== FALSE) + { + ob_clean(); + } + // default url is on html format + $url = html_entity_decode($url); + header('Request-URI: '.$url); + header('Content-Location: '.$url); + header('Location: '.$url); + exit(); +} + +/** + * Redirects to the given URL (HTML method) + * + * Note : once this function called, the execution doesn't go further + * (presence of an exit() instruction. + * + * @param string $url + * @param string $title_msg + * @param integer $refreh_time + * @return void + */ +function redirect_html( $url , $msg = '', $refresh_time = 0) +{ + global $user, $template, $lang_info, $conf, $lang, $t2, $page, $debug; + + if (!isset($lang_info)) + { + $user = build_user( $conf['guest_id'], true); + load_language('common.lang'); + trigger_action('loading_lang'); + load_language('local.lang'); + list($tmpl, $thm) = explode('/', get_default_template()); + $template = new Template(PHPWG_ROOT_PATH.'template/'.$tmpl, $thm); + } + else + { + $template = new Template(PHPWG_ROOT_PATH.'template/'.$user['template'], $user['theme']); + } + + if (empty($msg)) + { + $redirect_msg = l10n('redirect_msg'); + } + else + { + $redirect_msg = $msg; + } + $redirect_msg = nl2br($redirect_msg); + + $refresh = $refresh_time; + $url_link = $url; + $title = 'redirection'; + + $template->set_filenames( array( 'redirect' => 'redirect.tpl' ) ); + + include( PHPWG_ROOT_PATH.'include/page_header.php' ); + + $template->set_filenames( array( 'redirect' => 'redirect.tpl' ) ); + $template->parse('redirect'); + + include( PHPWG_ROOT_PATH.'include/page_tail.php' ); + + exit(); +} + +/** + * Redirects to the given URL (Switch to HTTP method or HTML method) + * + * Note : once this function called, the execution doesn't go further + * (presence of an exit() instruction. + * + * @param string $url + * @param string $title_msg + * @param integer $refreh_time + * @return void + */ +function redirect( $url , $msg = '', $refresh_time = 0) +{ + global $conf; + + // with RefeshTime <> 0, only html must be used + if ($conf['default_redirect_method']=='http' + and $refresh_time==0 + and !headers_sent() + ) + { + redirect_http($url); + } + else + { + redirect_html($url, $msg, $refresh_time); + } +} + +/** + * returns $_SERVER['QUERY_STRING'] whitout keys given in parameters + * + * @param array $rejects + * @param boolean $escape - if true escape & to & (for html) + * @returns string + */ +function get_query_string_diff($rejects=array(), $escape=true) +{ + $query_string = ''; + + $str = $_SERVER['QUERY_STRING']; + parse_str($str, $vars); + + $is_first = true; + foreach ($vars as $key => $value) + { + if (!in_array($key, $rejects)) + { + $query_string.= $is_first ? '?' : ($escape ? '&' : '&' ); + $is_first = false; + $query_string.= $key.'='.$value; + } + } + + return $query_string; +} + +function url_is_remote($url) +{ + if ( strncmp($url, 'http://', 7)==0 + or strncmp($url, 'https://', 8)==0 ) + { + return true; + } + return false; +} + +/** + * returns available template/theme + */ +function get_pwg_themes() +{ + global $conf; + $themes = array(); + + $template_dir = PHPWG_ROOT_PATH.'template'; + + foreach (get_dirs($template_dir) as $template) + { + foreach (get_dirs($template_dir.'/'.$template.'/theme') as $theme) + { + if ( ($template.'/'.$theme) != $conf['admin_layout'] ) + array_push($themes, $template.'/'.$theme); + } + } + + return $themes; +} + +/* Returns the PATH to the thumbnail to be displayed. If the element does not + * have a thumbnail, the default mime image path is returned. The PATH can be + * used in the php script, but not sent to the browser. + * @param array element_info assoc array containing element info from db + * at least 'path', 'tn_ext' and 'id' should be present + */ +function get_thumbnail_path($element_info) +{ + $path = get_thumbnail_location($element_info); + if ( !url_is_remote($path) ) + { + $path = PHPWG_ROOT_PATH.$path; + } + return $path; +} + +/* Returns the URL of the thumbnail to be displayed. If the element does not + * have a thumbnail, the default mime image url is returned. The URL can be + * sent to the browser, but not used in the php script. + * @param array element_info assoc array containing element info from db + * at least 'path', 'tn_ext' and 'id' should be present + */ +function get_thumbnail_url($element_info) +{ + $path = get_thumbnail_location($element_info); + if ( !url_is_remote($path) ) + { + $path = embellish_url(get_root_url().$path); + } + + // plugins want another url ? + $path = trigger_event('get_thumbnail_url', $path, $element_info); + return $path; +} + +/* returns the relative path of the thumnail with regards to to the root +of piwigo (not the current page!).This function is not intended to be +called directly from code.*/ +function get_thumbnail_location($element_info) +{ + global $conf; + if ( !empty( $element_info['tn_ext'] ) ) + { + $path = substr_replace( + get_filename_wo_extension($element_info['path']), + '/thumbnail/'.$conf['prefix_thumbnail'], + strrpos($element_info['path'],'/'), + 1 + ); + $path.= '.'.$element_info['tn_ext']; + } + else + { + $path = get_themeconf('mime_icon_dir') + .strtolower(get_extension($element_info['path'])).'.png'; + } + + // plugins want another location ? + $path = trigger_event( 'get_thumbnail_location', $path, $element_info); + return $path; +} + +/* returns the title of the thumnail */ +function get_thumbnail_title($element_info) +{ + // message in title for the thumbnail + if (isset($element_info['file'])) + { + $thumbnail_title = $element_info['file']; + } + else + { + $thumbnail_title = ''; + } + + if (!empty($element_info['filesize'])) + { + $thumbnail_title .= ' : '.l10n_dec('%d Kb', '%d Kb', $element_info['filesize']); + } + + return $thumbnail_title; +} + +// my_error returns (or send to standard output) the message concerning the +// error occured for the last mysql query. +function my_error($header) +{ + global $conf; + + $error = '<pre>'; + $error.= $header; + $error.= '[mysql error '.mysql_errno().'] '; + $error.= mysql_error(); + $error.= '</pre>'; + + if ($conf['die_on_sql_error']) + { + die($error); + } + else + { + echo $error; + } +} + +/** + * creates an array based on a query, this function is a very common pattern + * used here + * + * @param string $query + * @param string $fieldname + * @return array + */ +function array_from_query($query, $fieldname) +{ + $array = array(); + + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($array, $row[$fieldname]); + } + + return $array; +} + +/** + * fill the current user caddie with given elements, if not already in + * caddie + * + * @param array elements_id + */ +function fill_caddie($elements_id) +{ + global $user; + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + + $query = ' +SELECT element_id + FROM '.CADDIE_TABLE.' + WHERE user_id = '.$user['id'].' +;'; + $in_caddie = array_from_query($query, 'element_id'); + + $caddiables = array_diff($elements_id, $in_caddie); + + $datas = array(); + + foreach ($caddiables as $caddiable) + { + array_push($datas, array('element_id' => $caddiable, + 'user_id' => $user['id'])); + } + + if (count($caddiables) > 0) + { + mass_inserts(CADDIE_TABLE, array('element_id','user_id'), $datas); + } +} + +/** + * returns the element name from its filename + * + * @param string filename + * @return string name + */ +function get_name_from_file($filename) +{ + return str_replace('_',' ',get_filename_wo_extension($filename)); +} + +/** + * returns the corresponding value from $lang if existing. Else, the key is + * returned + * + * @param string key + * @return string + */ +function l10n($key) +{ + global $lang, $conf; + + if ($conf['debug_l10n'] and !isset($lang[$key]) and !empty($key)) + { + trigger_error('[l10n] language key "'.$key.'" is not defined', E_USER_NOTICE); + } + + return isset($lang[$key]) ? $lang[$key] : $key; +} + +/** + * returns the prinft value for strings including %d + * return is concorded with decimal value (singular, plural) + * + * @param singular string key + * @param plural string key + * @param decimal value + * @return string + */ +function l10n_dec($singular_fmt_key, $plural_fmt_key, $decimal) +{ + global $lang_info; + + return + sprintf( + l10n(( + (($decimal > 1) or ($decimal == 0 and $lang_info['zero_plural'])) + ? $plural_fmt_key + : $singular_fmt_key + )), $decimal); +} +/* + * returns a single element to use with l10n_args + * + * @param string key: translation key + * @param array/string/../number args: + * arguments to use on sprintf($key, args) + * if args is a array, each values are used on sprintf + * @return string + */ +function get_l10n_args($key, $args) +{ + if (is_array($args)) + { + $key_arg = array_merge(array($key), $args); + } + else + { + $key_arg = array($key, $args); + } + return array('key_args' => $key_arg); +} + +/* + * returns a string with formated with l10n_args elements + * + * @param element/array $key_args: element or array of l10n_args elements + * @param $sep: if $key_args is array, + * separator is used when translated l10n_args elements are concated + * @return string + */ +function l10n_args($key_args, $sep = "\n") +{ + if (is_array($key_args)) + { + foreach ($key_args as $key => $element) + { + if (isset($result)) + { + $result .= $sep; + } + else + { + $result = ''; + } + + if ($key === 'key_args') + { + array_unshift($element, l10n(array_shift($element))); + $result .= call_user_func_array('sprintf', $element); + } + else + { + $result .= l10n_args($element, $sep); + } + } + } + else + { + die('l10n_args: Invalid arguments'); + } + + return $result; +} + +/** + * returns the corresponding value from $themeconf if existing. Else, the + * key is returned + * + * @param string key + * @return string + */ +function get_themeconf($key) +{ + global $template; + + return $template->get_themeconf($key); +} + +/** + * Returns webmaster mail address depending on $conf['webmaster_id'] + * + * @return string + */ +function get_webmaster_mail_address() +{ + global $conf; + + $query = ' +SELECT '.$conf['user_fields']['email'].' + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['id'].' = '.$conf['webmaster_id'].' +;'; + list($email) = mysql_fetch_array(pwg_query($query)); + + return $email; +} + +/** + * which upgrades are available ? + * + * @return array + */ +function get_available_upgrade_ids() +{ + $upgrades_path = PHPWG_ROOT_PATH.'install/db'; + + $available_upgrade_ids = array(); + + if ($contents = opendir($upgrades_path)) + { + while (($node = readdir($contents)) !== false) + { + if (is_file($upgrades_path.'/'.$node) + and preg_match('/^(.*?)-database\.php$/', $node, $match)) + { + array_push($available_upgrade_ids, $match[1]); + } + } + } + natcasesort($available_upgrade_ids); + + return $available_upgrade_ids; +} + +/** + * Add configuration parameters from database to global $conf array + * + * @return void + */ +function load_conf_from_db($condition = '') +{ + global $conf; + + $query = ' +SELECT param, value + FROM '.CONFIG_TABLE.' + '.(!empty($condition) ? 'WHERE '.$condition : '').' +;'; + $result = pwg_query($query); + + if ((mysql_num_rows($result) == 0) and !empty($condition)) + { + die('No configuration data'); + } + + while ($row = mysql_fetch_array($result)) + { + $conf[ $row['param'] ] = isset($row['value']) ? $row['value'] : ''; + + // If the field is true or false, the variable is transformed into a + // boolean value. + if ($conf[$row['param']] == 'true' or $conf[$row['param']] == 'false') + { + $conf[ $row['param'] ] = get_boolean($conf[ $row['param'] ]); + } + } +} + +/** + * Prepends and appends a string at each value of the given array. + * + * @param array + * @param string prefix to each array values + * @param string suffix to each array values + */ +function prepend_append_array_items($array, $prepend_str, $append_str) +{ + array_walk( + $array, + create_function('&$s', '$s = "'.$prepend_str.'".$s."'.$append_str.'";') + ); + + return $array; +} + +/** + * creates an hashed based on a query, this function is a very common + * pattern used here. Among the selected columns fetched, choose one to be + * the key, another one to be the value. + * + * @param string $query + * @param string $keyname + * @param string $valuename + * @return array + */ +function simple_hash_from_query($query, $keyname, $valuename) +{ + $array = array(); + + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + $array[ $row[$keyname] ] = $row[$valuename]; + } + + return $array; +} + +/** + * creates an hashed based on a query, this function is a very common + * pattern used here. The key is given as parameter, the value is an associative + * array. + * + * @param string $query + * @param string $keyname + * @return array + */ +function hash_from_query($query, $keyname) +{ + $array = array(); + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $array[ $row[$keyname] ] = $row; + } + return $array; +} + +/** + * Return basename of the current script + * Lower case convertion is applied on return value + * Return value is without file extention ".php" + * + * @param void + * + * @return script basename + */ +function script_basename() +{ + global $conf; + + foreach (array('SCRIPT_NAME', 'SCRIPT_FILENAME', 'PHP_SELF') as $value) + { + $continue = !empty($_SERVER[$value]); + if ($continue) + { + $filename = strtolower($_SERVER[$value]); + + if ($conf['php_extension_in_urls']) + { + $continue = get_extension($filename) === 'php'; + } + + if ($continue) + { + $basename = basename($filename, '.php'); + $continue = !empty($basename); + } + + if ($continue) + { + return $basename; + } + } + } + + return ''; +} + +/** + * Return value for the current page define on $conf['filter_pages'] + * Îf value is not defined, default value are returned + * + * @param value name + * + * @return filter page value + */ +function get_filter_page_value($value_name) +{ + global $conf; + + $page_name = script_basename(); + + if (isset($conf['filter_pages'][$page_name][$value_name])) + { + return $conf['filter_pages'][$page_name][$value_name]; + } + else if (isset($conf['filter_pages']['default'][$value_name])) + { + return $conf['filter_pages']['default'][$value_name]; + } + else + { + return null; + } +} + +/** + * returns the character set of data sent to browsers / received from forms + */ +function get_pwg_charset() +{ + defined('PWG_CHARSET') or die('load_language PWG_CHARSET undefined'); + return PWG_CHARSET; +} + +/** + * includes a language file or returns the content of a language file + * availability of the file + * + * in descending order of preference: + * param language, user language, default language + * Piwigo default language. + * + * @param string filename + * @param string dirname + * @param string language + * @param bool return_content - if true the file content is returned otherwise + * the file is evaluated as php + * @return boolean success status or a string if return_content is true + */ +function load_language($filename, $dirname = '', $language = '', + $return_content=false, $target_charset=null) +{ + global $user; + + if (!$return_content) + { + $filename .= '.php'; //MAYBE to do .. load .po and .mo localization files + } + if (empty($dirname)) + { + $dirname = PHPWG_ROOT_PATH; + } + $dirname .= 'language/'; + + $languages = array(); + if ( !empty($language) ) + { + $languages[] = $language; + } + if ( !empty($user['language']) ) + { + $languages[] = $user['language']; + } + if ( defined('PHPWG_INSTALLED') ) + { + $languages[] = get_default_language(); + } + $languages[] = PHPWG_DEFAULT_LANGUAGE; + $languages = array_unique($languages); + + if ( empty($target_charset) ) + { + $target_charset = get_pwg_charset(); + } + $target_charset = strtolower($target_charset); + $source_charset = ''; + $source_file = ''; + foreach ($languages as $language) + { + $dir = $dirname.$language; + + // exact charset match - no conversion required + $f = $dir.'.'.$target_charset.'/'.$filename; + if (file_exists($f)) + { + $source_file = $f; + break; + } + + // UTF-8 ? + $f = $dir.'/'.$filename; + if (file_exists($f)) + { + $source_charset = 'utf-8'; + $source_file = $f; + break; + } + + if ($target_charset=='utf-8') + { // we accept conversion from ISO-8859-1 to UTF-8 + $f = $dir.'.iso-8859-1/'.$filename; + if (file_exists($f)) + { + $source_charset = 'iso-8859-1'; + $source_file = $f; + break; + } + } + } + + if ( !empty($source_file) ) + { + if (!$return_content) + { + @include($source_file); + $load_lang = @$lang; + $load_lang_info = @$lang_info; + + global $lang, $lang_info; + if ( !isset($lang) ) $lang=array(); + if ( !isset($lang_info) ) $lang_info=array(); + + if ( !empty($source_charset) and $source_charset!=$target_charset) + { + if ( is_array($load_lang) ) + { + foreach ($load_lang as $k => $v) + { + if ( is_array($v) ) + { + $func = create_function('$v', 'return convert_charset($v, "'.$source_charset.'","'.$target_charset.'");' ); + $lang[$k] = array_map($func, $v); + } + else + $lang[$k] = convert_charset($v, $source_charset, $target_charset); + } + } + if ( is_array($load_lang_info) ) + { + foreach ($load_lang_info as $k => $v) + { + $lang_info[$k] = convert_charset($v, $source_charset, $target_charset); + } + } + } + else + { + $lang = array_merge( $lang, (array)$load_lang ); + $lang_info = array_merge( $lang_info, (array)$load_lang_info ); + } + return true; + } + else + { + $content = @file_get_contents($source_file); + if ( !empty($source_charset) and $source_charset!=$target_charset) + { + $content = convert_charset($content, $source_charset, $target_charset); + } + return $content; + } + } + return false; +} + +/** + * converts a string from a character set to another character set + * @param string str the string to be converted + * @param string source_charset the character set in which the string is encoded + * @param string dest_charset the destination character set + */ +function convert_charset($str, $source_charset, $dest_charset) +{ + if ($source_charset==$dest_charset) + return $str; + if ($source_charset=='iso-8859-1' and $dest_charset=='utf-8') + { + return utf8_encode($str); + } + if ($source_charset=='utf-8' and $dest_charset=='iso-8859-1') + { + return utf8_decode($str); + } + if (function_exists('iconv')) + { + return iconv($source_charset, $dest_charset, $str); + } + if (function_exists('mb_convert_encoding')) + { + return mb_convert_encoding( $str, $dest_charset, $source_charset ); + } + return $str; //??? +} +?>
\ No newline at end of file diff --git a/BSF/include/functions_calendar.inc.php b/BSF/include/functions_calendar.inc.php new file mode 100644 index 000000000..baa72b927 --- /dev/null +++ b/BSF/include/functions_calendar.inc.php @@ -0,0 +1,295 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +define('CAL_VIEW_LIST', 'list'); +define('CAL_VIEW_CALENDAR', 'calendar'); + +function initialize_calendar() +{ + global $page, $conf, $user, $template, $filter; + +//------------------ initialize the condition on items to take into account --- + $inner_sql = ' FROM ' . IMAGES_TABLE; + + if ($page['section']=='categories') + { // we will regenerate the items by including subcats elements + $page['items'] = array(); + $inner_sql .= ' +INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id = image_id'; + + if ( isset($page['category']) ) + { + $sub_ids = array_diff( + get_subcat_ids(array($page['category']['id'])), + explode(',', $user['forbidden_categories']) + ); + + if (empty($sub_ids)) + { + return; // nothing to do + } + $inner_sql .= ' +WHERE category_id IN ('.implode(',',$sub_ids).')'; + $inner_sql .= ' + '.get_sql_condition_FandF + ( + array + ( + 'visible_images' => 'id' + ), + 'AND', false + ); + } + else + { + $inner_sql .= ' + '.get_sql_condition_FandF + ( + array + ( + 'forbidden_categories' => 'category_id', + 'visible_categories' => 'category_id', + 'visible_images' => 'id' + ), + 'WHERE', true + ); + } + } + else + { + if ( empty($page['items']) ) + { + return; // nothing to do + } + $inner_sql .= ' +WHERE id IN (' . implode(',',$page['items']) .')'; + } + +//-------------------------------------- initialize the calendar parameters --- + pwg_debug('start initialize_calendar'); + + $fields = array( + // Created + 'created' => array( + 'label' => l10n('Creation date'), + ), + // Posted + 'posted' => array( + 'label' => l10n('Post date'), + ), + ); + + $styles = array( + // Monthly style + 'monthly' => array( + 'include' => 'calendar_monthly.class.php', + 'view_calendar' => true, + ), + // Weekly style + 'weekly' => array( + 'include' => 'calendar_weekly.class.php', + 'view_calendar' => false, + ), + ); + + $views = array(CAL_VIEW_LIST,CAL_VIEW_CALENDAR); + + // Retrieve calendar field + if ( !isset( $fields[ $page['chronology_field'] ] ) ) + { + die('bad chronology field'); + } + + // Retrieve style + if ( !isset( $styles[ $page['chronology_style'] ] ) ) + { + $page['chronology_style'] = 'monthly'; + } + $cal_style = $page['chronology_style']; + include(PHPWG_ROOT_PATH.'include/'. $styles[$cal_style]['include']); + $calendar = new Calendar(); + + // Retrieve view + + if ( !isset($page['chronology_view']) or + !in_array( $page['chronology_view'], $views ) ) + { + $page['chronology_view'] = CAL_VIEW_LIST; + } + + if ( CAL_VIEW_CALENDAR==$page['chronology_view'] and + !$styles[$cal_style]['view_calendar'] ) + { + + $page['chronology_view'] = CAL_VIEW_LIST; + } + + // perform a sanity check on $requested + if (!isset($page['chronology_date'])) + { + $page['chronology_date'] = array(); + } + while ( count($page['chronology_date']) > 3) + { + array_pop($page['chronology_date']); + } + + $any_count = 0; + for ($i = 0; $i < count($page['chronology_date']); $i++) + { + if ($page['chronology_date'][$i] == 'any') + { + if ($page['chronology_view'] == CAL_VIEW_CALENDAR) + {// we dont allow any in calendar view + while ($i < count($page['chronology_date'])) + { + array_pop($page['chronology_date']); + } + break; + } + $any_count++; + } + elseif ($page['chronology_date'][$i] == '') + { + while ($i < count($page['chronology_date'])) + { + array_pop($page['chronology_date']); + } + } + else + { + $page['chronology_date'][$i] = (int)$page['chronology_date'][$i]; + } + } + if ($any_count == 3) + { + array_pop($page['chronology_date']); + } + + $calendar->initialize($inner_sql); + + //echo ('<pre>'. var_export($calendar, true) . '</pre>'); + + $must_show_list = true; // true until calendar generates its own display + if (script_basename() != 'picture') // basename without file extention + { + if ($calendar->generate_category_content()) + { + $page['items'] = array(); + $must_show_list = false; + } + + $page['comment'] = ''; + $template->assign('FILE_CHRONOLOGY_VIEW', 'month_calendar.tpl'); + + foreach ($styles as $style => $style_data) + { + foreach ($views as $view) + { + if ( $style_data['view_calendar'] or $view != CAL_VIEW_CALENDAR) + { + $selected = false; + + if ($style!=$cal_style) + { + $chronology_date = array(); + if ( isset($page['chronology_date'][0]) ) + { + array_push($chronology_date, $page['chronology_date'][0]); + } + } + else + { + $chronology_date = $page['chronology_date']; + } + $url = duplicate_index_url( + array( + 'chronology_style' => $style, + 'chronology_view' => $view, + 'chronology_date' => $chronology_date, + ) + ); + + if ($style==$cal_style and $view==$page['chronology_view'] ) + { + $selected = true; + } + + $template->append( + 'chronology_views', + array( + 'VALUE' => $url, + 'CONTENT' => l10n('chronology_'.$style.'_'.$view), + 'SELECTED' => $selected, + ) + ); + } + } + } + $url = duplicate_index_url( + array(), array('start', 'chronology_date') + ); + $calendar_title = '<a href="'.$url.'">' + .$fields[$page['chronology_field']]['label'].'</a>'; + $calendar_title.= $calendar->get_display_name(); + $template->assign('chronology', + array( + 'TITLE' => $calendar_title + ) + ); + } // end category calling + + if ($must_show_list) + { + $query = 'SELECT DISTINCT(id)'; + $query .= $calendar->inner_sql.' + '.$calendar->get_date_where(); + if ( isset($page['super_order_by']) ) + { + $query .= ' + '.$conf['order_by']; + } + else + { + if ( count($page['chronology_date'])==0 + or in_array('any', $page['chronology_date']) ) + {// selected period is very big so we show newest first + $order = ' DESC, '; + } + else + {// selected period is small (month,week) so we show oldest first + $order = ' ASC, '; + } + $order_by = str_replace( + 'ORDER BY ', + 'ORDER BY '.$calendar->date_field.$order, $conf['order_by'] + ); + $query .= ' + '.$order_by; + } + $page['items'] = array_from_query($query, 'id'); + } + pwg_debug('end initialize_calendar'); +} + +?>
\ No newline at end of file diff --git a/BSF/include/functions_category.inc.php b/BSF/include/functions_category.inc.php new file mode 100644 index 000000000..721cc0038 --- /dev/null +++ b/BSF/include/functions_category.inc.php @@ -0,0 +1,509 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * Provides functions to handle categories. + * + * + */ + +/** + * Is the category accessible to the connected user ? + * + * Note : if the user is not authorized to see this category, page creation + * ends (exit command in this function) + * + * @param int category id to verify + * @return void + */ +function check_restrictions($category_id) +{ + global $user; + + // $filter['visible_categories'] and $filter['visible_images'] + // are not used because it's not necessary (filter <> restriction) + if (in_array($category_id, explode(',', $user['forbidden_categories']))) + { + access_denied(); + } +} + +function get_categories_menu() +{ + global $page, $user, $filter; + + $query = ' +SELECT '; + // From CATEGORIES_TABLE + $query.= ' + id, name, permalink, nb_images, global_rank,'; + // From USER_CACHE_CATEGORIES_TABLE + $query.= ' + date_last, max_date_last, count_images, count_categories'; + + // $user['forbidden_categories'] including with USER_CACHE_CATEGORIES_TABLE + $query.= ' +FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' + ON id = cat_id and user_id = '.$user['id']; + + // Always expand when filter is activated + if (!$user['expand'] and !$filter['enabled']) + { + $where = ' +(id_uppercat is NULL'; + if (isset($page['category'])) + { + $where .= ' OR id_uppercat IN ('.$page['category']['uppercats'].')'; + } + $where .= ')'; + } + else + { + $where = ' + '.get_sql_condition_FandF + ( + array + ( + 'visible_categories' => 'id', + ), + null, + true + ); + } + + $where = trigger_event('get_categories_menu_sql_where', + $where, $user['expand'], $filter['enabled'] ); + + $query.= ' +WHERE '.$where.' +;'; + + $result = pwg_query($query); + $cats = array(); + while ($row = mysql_fetch_assoc($result)) + { + array_push($cats, $row); + } + usort($cats, 'global_rank_compare'); + + // Update filtered data + if (function_exists('update_cats_with_filtered_data')) + { + update_cats_with_filtered_data($cats); + } + + return get_html_menu_category($cats, @$page['category'] ); +} + + +/** + * Retrieve informations about a category in the database + * + * Returns an array with following keys : + * + * - comment + * - dir : directory, might be empty for virtual categories + * - name : an array with indexes from 0 (lowest cat name) to n (most + * uppercat name findable) + * - nb_images + * - id_uppercat + * - site_id + * - + * + * @param int category id + * @return array + */ +function get_cat_info( $id ) +{ + $query = ' +SELECT * + FROM '.CATEGORIES_TABLE.' + WHERE id = '.$id.' +;'; + $cat = mysql_fetch_assoc(pwg_query($query)); + if (empty($cat)) + return null; + + foreach ($cat as $k => $v) + { + // If the field is true or false, the variable is transformed into a + // boolean value. + if ($cat[$k] == 'true' or $cat[$k] == 'false') + { + $cat[$k] = get_boolean( $cat[$k] ); + } + } + + $upper_ids = explode(',', $cat['uppercats']); + if ( count($upper_ids)==1 ) + {// no need to make a query for level 1 + $cat['upper_names'] = array( + array( + 'id' => $cat['id'], + 'name' => $cat['name'], + 'permalink' => $cat['permalink'], + ) + ); + } + else + { + $names = array(); + $query = ' + SELECT id, name, permalink + FROM '.CATEGORIES_TABLE.' + WHERE id IN ('.$cat['uppercats'].') + ;'; + $names = hash_from_query($query, 'id'); + + // category names must be in the same order than uppercats list + $cat['upper_names'] = array(); + foreach ($upper_ids as $cat_id) + { + array_push( $cat['upper_names'], $names[$cat_id]); + } + } + return $cat; +} + +// get_complete_dir returns the concatenation of get_site_url and +// get_local_dir +// Example : "pets > rex > 1_year_old" is on the the same site as the +// Piwigo files and this category has 22 for identifier +// get_complete_dir(22) returns "./galleries/pets/rex/1_year_old/" +function get_complete_dir( $category_id ) +{ + return get_site_url($category_id).get_local_dir($category_id); +} + +// get_local_dir returns an array with complete path without the site url +// Example : "pets > rex > 1_year_old" is on the the same site as the +// Piwigo files and this category has 22 for identifier +// get_local_dir(22) returns "pets/rex/1_year_old/" +function get_local_dir( $category_id ) +{ + global $page; + + $uppercats = ''; + $local_dir = ''; + + if ( isset( $page['plain_structure'][$category_id]['uppercats'] ) ) + { + $uppercats = $page['plain_structure'][$category_id]['uppercats']; + } + else + { + $query = 'SELECT uppercats'; + $query.= ' FROM '.CATEGORIES_TABLE.' WHERE id = '.$category_id; + $query.= ';'; + $row = mysql_fetch_array( pwg_query( $query ) ); + $uppercats = $row['uppercats']; + } + + $upper_array = explode( ',', $uppercats ); + + $database_dirs = array(); + $query = 'SELECT id,dir'; + $query.= ' FROM '.CATEGORIES_TABLE.' WHERE id IN ('.$uppercats.')'; + $query.= ';'; + $result = pwg_query( $query ); + while( $row = mysql_fetch_array( $result ) ) + { + $database_dirs[$row['id']] = $row['dir']; + } + foreach ($upper_array as $id) + { + $local_dir.= $database_dirs[$id].'/'; + } + + return $local_dir; +} + +// retrieving the site url : "http://domain.com/gallery/" or +// simply "./galleries/" +function get_site_url($category_id) +{ + global $page; + + $query = ' +SELECT galleries_url + FROM '.SITES_TABLE.' AS s,'.CATEGORIES_TABLE.' AS c + WHERE s.id = c.site_id + AND c.id = '.$category_id.' +;'; + $row = mysql_fetch_array(pwg_query($query)); + return $row['galleries_url']; +} + +// returns an array of image orders available for users/visitors +function get_category_preferred_image_orders() +{ + global $conf; + return array( + array(l10n('default_sort'), '', true), + array(l10n('Average rate'), 'average_rate DESC', $conf['rate']), + array(l10n('most_visited_cat'), 'hit DESC', true), + array(l10n('Creation date'), 'date_creation DESC', true), + array(l10n('Post date'), 'date_available DESC', true), + array(l10n('File name'), 'file ASC', true) + ); +} + +function display_select_categories($categories, + $selecteds, + $blockname, + $fullname = true) +{ + global $template; + + $tpl_cats = array(); + foreach ($categories as $category) + { + if ($fullname) + { + $option = get_cat_display_name_cache($category['uppercats'], + null, + false); + } + else + { + $option = str_repeat(' ', + (3 * substr_count($category['global_rank'], '.'))); + $option.= '- '.$category['name']; + } + $tpl_cats[ $category['id'] ] = $option; + } + + $template->assign( $blockname, $tpl_cats); + $template->assign( $blockname.'_selected', $selecteds); +} + +function display_select_cat_wrapper($query, $selecteds, $blockname, + $fullname = true) +{ + $result = pwg_query($query); + $categories = array(); + if (!empty($result)) + { + while ($row = mysql_fetch_assoc($result)) + { + array_push($categories, $row); + } + } + usort($categories, 'global_rank_compare'); + display_select_categories($categories, $selecteds, $blockname, $fullname); +} + +/** + * returns all subcategory identifiers of given category ids + * + * @param array ids + * @return array + */ +function get_subcat_ids($ids) +{ + $query = ' +SELECT DISTINCT(id) + FROM '.CATEGORIES_TABLE.' + WHERE '; + foreach ($ids as $num => $category_id) + { + is_numeric($category_id) + or trigger_error( + 'get_subcat_ids expecting numeric, not '.gettype($category_id), + E_USER_WARNING + ); + if ($num > 0) + { + $query.= ' + OR '; + } + $query.= 'uppercats REGEXP \'(^|,)'.$category_id.'(,|$)\''; + } + $query.= ' +;'; + $result = pwg_query($query); + + $subcats = array(); + while ($row = mysql_fetch_array($result)) + { + array_push($subcats, $row['id']); + } + return $subcats; +} + +/** finds a matching category id from a potential list of permalinks + * @param array permalinks example: holiday holiday/france holiday/france/paris + * @param int idx - output of the index in $permalinks that matches + * return category id or null if no match + */ +function get_cat_id_from_permalinks( $permalinks, &$idx ) +{ + $in = ''; + foreach($permalinks as $permalink) + { + if ( !empty($in) ) $in.=', '; + $in .= '"'.$permalink.'"'; + } + $query =' +SELECT cat_id AS id, permalink, 1 AS is_old + FROM '.OLD_PERMALINKS_TABLE.' + WHERE permalink IN ('.$in.') +UNION +SELECT id, permalink, 0 AS is_old + FROM '.CATEGORIES_TABLE.' + WHERE permalink IN ('.$in.') +;'; + $perma_hash = hash_from_query($query, 'permalink'); + + if ( empty($perma_hash) ) + return null; + for ($i=count($permalinks)-1; $i>=0; $i--) + { + if ( isset( $perma_hash[ $permalinks[$i] ] ) ) + { + $idx = $i; + $cat_id = $perma_hash[ $permalinks[$i] ]['id']; + if ($perma_hash[ $permalinks[$i] ]['is_old']) + { + $query=' +UPDATE '.OLD_PERMALINKS_TABLE.' SET last_hit=NOW(), hit=hit+1 + WHERE permalink="'.$permalinks[$i].'" AND cat_id='.$cat_id.' + LIMIT 1'; + pwg_query($query); + } + return $cat_id; + } + } + return null; +} + +function global_rank_compare($a, $b) +{ + return strnatcasecmp($a['global_rank'], $b['global_rank']); +} + +function rank_compare($a, $b) +{ + if ($a['rank'] == $b['rank']) + { + return 0; + } + + return ($a['rank'] < $b['rank']) ? -1 : 1; +} + +/** + * returns display text for information images of category + * + * @param array categories + * @return string + */ +function get_display_images_count($cat_nb_images, $cat_count_images, $cat_count_categories, $short_message = true, $Separator = '\n') +{ + $display_text = ''; + + if ($cat_count_images > 0) + { + if ($cat_nb_images > 0 and $cat_nb_images < $cat_count_images) + { + $display_text.= get_display_images_count($cat_nb_images, $cat_nb_images, 0, $short_message, $Separator).$Separator; + $cat_count_images-= $cat_nb_images; + $cat_nb_images = 0; + } + + //at least one image direct or indirect + $display_text.= l10n_dec('%d element', '%d elements', $cat_count_images); + + if ($cat_count_categories == 0 or $cat_nb_images == $cat_count_images) + { + //no descendant categories or descendants do not contain images + if (! $short_message) + { + $display_text.= ' '.l10n('images_available_cpl'); + } + } + else + { + $display_text.= ' '.l10n_dec('images_available_cat', 'images_available_cats', $cat_count_categories); + } + } + + return $display_text; +} + +/** + * returns the link of upload menu + * + * @param null + * @return string or null + */ +function get_upload_menu_link() +{ + global $conf, $page, $user; + + $show_link = false; + $arg_link = null; + + if (is_autorize_status($conf['upload_user_access'])) + { + if (isset($page['category']) and $page['category']['uploadable'] ) + { + // upload a picture in the category + $show_link = true; + $arg_link = 'cat='.$page['category']['id']; + } + else + if ($conf['upload_link_everytime']) + { + // upload a picture in the category + $query = ' +SELECT + 1 +FROM '.CATEGORIES_TABLE.' INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' + ON id = cat_id and user_id = '.$user['id'].' +WHERE + uploadable = \'true\' + '.get_sql_condition_FandF + ( + array + ( + 'visible_categories' => 'id', + ), + 'AND' + ).' +LIMIT 1'; + + $show_link = mysql_num_rows(pwg_query($query)) <> 0; + } + } + if ($show_link) + { + return get_root_url().'upload.php'.(empty($arg_link) ? '' : '?'.$arg_link); + } + else + { + return; + } +} + +?> diff --git a/BSF/include/functions_comment.inc.php b/BSF/include/functions_comment.inc.php new file mode 100644 index 000000000..6e6498c38 --- /dev/null +++ b/BSF/include/functions_comment.inc.php @@ -0,0 +1,228 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * returns a "secret key" that is to be sent back when a user enters a comment + */ +function get_comment_post_key($image_id) +{ + global $conf; + + $time = time(); + + return sprintf( + '%s:%s', + $time, + hash_hmac( + 'md5', + $time.':'.$image_id, + $conf['secret_key'] + ) + ); +} + +//returns string action to perform on a new comment: validate, moderate, reject +function user_comment_check($action, $comment) +{ + global $conf,$user; + + if ($action=='reject') + return $action; + + $my_action = $conf['comment_spam_reject'] ? 'reject':'moderate'; + + if ($action==$my_action) + return $action; + + // we do here only BASIC spam check (plugins can do more) + if ( !is_a_guest() ) + return $action; + + $link_count = preg_match_all( '/https?:\/\//', + $comment['content'], $matches); + + if ( strpos($comment['author'], 'http://')!==false ) + { + $link_count++; + } + + if ( $link_count>$conf['comment_spam_max_links'] ) + return $my_action; + + return $action; +} + + +add_event_handler('user_comment_check', 'user_comment_check', + EVENT_HANDLER_PRIORITY_NEUTRAL, 2); + +/** + * Tries to insert a user comment in the database and returns one of : + * validate, moderate, reject + * @param array comm contains author, content, image_id + * @param string key secret key sent back to the browser + * @param array infos out array of messages + */ +function insert_user_comment( &$comm, $key, &$infos ) +{ + global $conf, $user; + + $comm = array_merge( $comm, + array( + 'ip' => $_SERVER['REMOTE_ADDR'], + 'agent' => $_SERVER['HTTP_USER_AGENT'] + ) + ); + + $infos = array(); + if (!$conf['comments_validation'] or is_admin()) + { + $comment_action='validate'; //one of validate, moderate, reject + } + else + { + $comment_action='moderate'; //one of validate, moderate, reject + } + + // display author field if the user status is guest or generic + if (!is_classic_user()) + { + if ( empty($comm['author']) ) + { + $comm['author'] = 'guest'; + } + // if a guest try to use the name of an already existing user, he must be + // rejected + if ( $comm['author'] != 'guest' ) + { + $query = ' +SELECT COUNT(*) AS user_exists + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['username']." = '".addslashes($comm['author'])."'"; + $row = mysql_fetch_assoc( pwg_query( $query ) ); + if ( $row['user_exists'] == 1 ) + { + array_push($infos, l10n('comment_user_exists') ); + $comment_action='reject'; + } + } + } + else + { + $comm['author'] = $user['username']; + } + if ( empty($comm['content']) ) + { // empty comment content + $comment_action='reject'; + } + + $key = explode( ':', @$key ); + if ( count($key)!=2 + or $key[0]>time()-2 // page must have been retrieved more than 2 sec ago + or $key[0]<time()-3600 // 60 minutes expiration + or hash_hmac( + 'md5', $key[0].':'.$comm['image_id'], $conf['secret_key'] + ) != $key[1] + ) + { + $comment_action='reject'; + } + + if ($comment_action!='reject' and $conf['anti-flood_time']>0 ) + { // anti-flood system + $reference_date = time() - $conf['anti-flood_time']; + $query = ' +SELECT id FROM '.COMMENTS_TABLE.' + WHERE date > FROM_UNIXTIME('.$reference_date.') + AND author = "'.addslashes($comm['author']).'"'; + if ( mysql_num_rows( pwg_query( $query ) ) > 0 ) + { + array_push( $infos, l10n('comment_anti-flood') ); + $comment_action='reject'; + } + } + + // perform more spam check + $comment_action = trigger_event('user_comment_check', + $comment_action, $comm + ); + + if ( $comment_action!='reject' ) + { + $query = ' +INSERT INTO '.COMMENTS_TABLE.' + (author, content, date, validated, validation_date, image_id) + VALUES ( + "'.addslashes($comm['author']).'", + "'.addslashes($comm['content']).'", + NOW(), + "'.($comment_action=='validate' ? 'true':'false').'", + '.($comment_action=='validate' ? 'NOW()':'NULL').', + '.$comm['image_id'].' + ) +'; + + pwg_query($query); + + $comm['id'] = mysql_insert_id(); + + if + ( + ($comment_action=='validate' and $conf['email_admin_on_comment']) + or + ($comment_action!='validate' and $conf['email_admin_on_comment_validation']) + ) + { + include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php'); + + $del_url = + get_absolute_root_url().'comments.php?delete='.$comm['id']; + + $keyargs_content = array + ( + get_l10n_args('Author: %s', $comm['author']), + get_l10n_args('Comment: %s', $comm['content']), + get_l10n_args('', ''), + get_l10n_args('Delete: %s', $del_url) + ); + + if ($comment_action!='validate') + { + $keyargs_content[] = + get_l10n_args('', ''); + $keyargs_content[] = + get_l10n_args('Validate: %s', + get_absolute_root_url().'comments.php?validate='.$comm['id']); + } + + pwg_mail_notification_admins + ( + get_l10n_args('Comment by %s', $comm['author']), + $keyargs_content + ); + } + } + return $comment_action; +} + +?>
\ No newline at end of file diff --git a/BSF/include/functions_cookie.inc.php b/BSF/include/functions_cookie.inc.php new file mode 100644 index 000000000..159a5b538 --- /dev/null +++ b/BSF/include/functions_cookie.inc.php @@ -0,0 +1,115 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// cookie_path returns the path to use for the Piwigo cookie. +// If Piwigo is installed on : +// http://domain.org/meeting/gallery/category.php +// cookie_path will return : "/meeting/gallery" +function cookie_path() +{ + if ( isset($_SERVER['REDIRECT_SCRIPT_NAME']) and + !empty($_SERVER['REDIRECT_SCRIPT_NAME']) ) + { + $scr = $_SERVER['REDIRECT_SCRIPT_NAME']; + } + else if ( isset($_SERVER['REDIRECT_URL']) ) + { + // mod_rewrite is activated for upper level directories. we must set the + // cookie to the path shown in the browser otherwise it will be discarded. + if + ( + isset($_SERVER['PATH_INFO']) and !empty($_SERVER['PATH_INFO']) and + ($_SERVER['REDIRECT_URL'] !== $_SERVER['PATH_INFO']) and + (substr($_SERVER['REDIRECT_URL'],-strlen($_SERVER['PATH_INFO'])) + == $_SERVER['PATH_INFO']) + ) + { + $scr = substr($_SERVER['REDIRECT_URL'], 0, + strlen($_SERVER['REDIRECT_URL'])-strlen($_SERVER['PATH_INFO'])); + } + else + { + $scr = $_SERVER['REDIRECT_URL']; + } + } + else + { + $scr = $_SERVER['SCRIPT_NAME']; + } + + $scr = substr($scr,0,strrpos( $scr,'/')); + + // add a trailing '/' if needed + if ((strlen($scr) == 0) or ($scr{strlen($scr)-1} !== '/')) + { + $scr .= '/'; + } + + if ( substr(PHPWG_ROOT_PATH,0,3)=='../') + { // this is maybe a plugin inside pwg directory + // TODO - what if it is an external script outside PWG ? + $scr = $scr.PHPWG_ROOT_PATH; + while (1) + { + $new = preg_replace('#[^/]+/\.\.(/|$)#', '', $scr); + if ($new==$scr) + { + break; + } + $scr=$new; + } + } + return $scr; +} + +/** + * persistently stores a variable in pwg cookie + * @return boolean true on success + * @see pwg_get_cookie_var + */ +function pwg_set_cookie_var($var, $value) +{ + $_COOKIE['pwg_'.$var] = $value; + return + setcookie('pwg_'.$var, $value, + strtotime('+10 years'), cookie_path()); +} + +/** + * retrieves the value of a persistent variable in pwg cookie + * @return mixed + * @see pwg_set_cookie_var + */ +function pwg_get_cookie_var($var, $default = null) +{ + if (isset($_COOKIE['pwg_'.$var])) + { + return $_COOKIE['pwg_'.$var]; + } + else + { + return $default; + } +} + +?> diff --git a/BSF/include/functions_filter.inc.php b/BSF/include/functions_filter.inc.php new file mode 100644 index 000000000..24efb0994 --- /dev/null +++ b/BSF/include/functions_filter.inc.php @@ -0,0 +1,63 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + + +/** + * Get a check key for filtered data + * Check key are composed of elements witch force to compute data + * + * @param null + * @return strinf check_key + */ +function get_filter_check_key() +{ + global $user, $filter; + + return $user['id'].$filter['recent_period'].date('Ymd'); +} + +/** + * update data of categories with filtered values + * + * @param array list of categories + * @return null + */ +function update_cats_with_filtered_data(&$cats) +{ + global $filter; + + if ($filter['enabled']) + { + $upd_fields = array('date_last', 'max_date_last', 'count_images', 'count_categories', 'nb_images'); + + foreach ($cats as $cat_id => $category) + { + foreach ($upd_fields as $upd_field) + { + $cats[$cat_id][$upd_field] = $filter['categories'][$category['id']][$upd_field]; + } + } + } +} + +?> diff --git a/BSF/include/functions_group.inc.php b/BSF/include/functions_group.inc.php new file mode 100644 index 000000000..a5c07b5b5 --- /dev/null +++ b/BSF/include/functions_group.inc.php @@ -0,0 +1,26 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// with 1.5 preparation, no group dedicated function is used. + +?> diff --git a/BSF/include/functions_html.inc.php b/BSF/include/functions_html.inc.php new file mode 100644 index 000000000..b51f6f9df --- /dev/null +++ b/BSF/include/functions_html.inc.php @@ -0,0 +1,751 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +function get_icon($date, $is_child_date = false) +{ + global $page, $user; + + if (empty($date)) + { + return ''; + } + + if (isset($page['get_icon_cache'][$date])) + { + if (! $page['get_icon_cache'][$date] ) + return ''; + return $page['get_icon_cache']['_icons_'][$is_child_date]; + } + + if (!isset($page['get_icon_cache']['sql_recent_date'])) + { + // Use MySql date in order to standardize all recent "actions/queries" + list($page['get_icon_cache']['sql_recent_date']) = + mysql_fetch_array(pwg_query('select SUBDATE( + CURRENT_DATE,INTERVAL '.$user['recent_period'].' DAY)')); + } + + $page['get_icon_cache'][$date] = false; + if ( $date > $page['get_icon_cache']['sql_recent_date'] ) + { + if ( !isset($page['get_icon_cache']['_icons_'] ) ) + { + $icons = array(false => 'recent', true => 'recent_by_child' ); + $title = sprintf( + l10n('elements posted during the last %d days'), + $user['recent_period'] + ); + foreach ($icons as $key => $icon) + { + $icon_url = get_themeconf('icon_dir').'/'.$icon.'.png'; + $size = getimagesize( PHPWG_ROOT_PATH.$icon_url ); + $icon_url = get_root_url().$icon_url; + $output = '<img title="'.$title.'" src="'.$icon_url.'" class="icon" style="border:0;'; + $output.= 'height:'.$size[1].'px;width:'.$size[0].'px" alt="(!)" />'; + $page['get_icon_cache']['_icons_'][$key] = $output; + } + } + $page['get_icon_cache'][$date] = true; + } + + if (! $page['get_icon_cache'][$date] ) + return ''; + return $page['get_icon_cache']['_icons_'][$is_child_date]; +} + +function create_navigation_bar( + $url, $nb_element, $start, $nb_element_page, $clean_url = false + ) +{ + global $conf; + + $pages_around = $conf['paginate_pages_around']; + $start_str = $clean_url ? '/start-' : + ( ( strstr($url, '?')===false ? '?':'&') . 'start=' ); + + $navbar = ''; + + // current page detection + if (!isset($start) + or !is_numeric($start) + or (is_numeric($start) and $start < 0)) + { + $start = 0; + } + + // navigation bar useful only if more than one page to display ! + if ($nb_element > $nb_element_page) + { + // current page and last page + $cur_page = ceil($start / $nb_element_page) + 1; + $maximum = ceil($nb_element / $nb_element_page); + + // link to first page ? + if ($cur_page != 1) + { + $navbar.= + '<a href="'.$url.'" rel="first">' + .l10n('first_page') + .'</a>'; + } + else + { + $navbar.= l10n('first_page'); + } + $navbar.= ' | '; + // link on previous page ? + if ($start != 0) + { + $previous = $start - $nb_element_page; + + $navbar.= + '<a href="' + .$url.($previous > 0 ? $start_str.$previous : '') + .'" rel="prev">' + .l10n('previous_page') + .'</a>'; + } + else + { + $navbar.= l10n('previous_page'); + } + $navbar.= ' |'; + + if ($cur_page > $pages_around + 1) + { + $navbar.= ' <a href="'.$url.'">1</a>'; + + if ($cur_page > $pages_around + 2) + { + $navbar.= ' ...'; + } + } + + // inspired from punbb source code + for ($i = $cur_page - $pages_around, $stop = $cur_page + $pages_around + 1; + $i < $stop; + $i++) + { + if ($i < 1 or $i > $maximum) + { + continue; + } + else if ($i != $cur_page) + { + $temp_start = ($i - 1) * $nb_element_page; + + $navbar.= + ' ' + .'<a href="'.$url + .($temp_start > 0 ? $start_str.$temp_start : '') + .'">' + .$i + .'</a>'; + } + else + { + $navbar.= + ' ' + .'<span class="pageNumberSelected">' + .$i + .'</span>'; + } + } + + if ($cur_page < ($maximum - $pages_around)) + { + $temp_start = ($maximum - 1) * $nb_element_page; + + if ($cur_page < ($maximum - $pages_around - 1)) + { + $navbar.= ' ...'; + } + + $navbar.= ' <a href="'.$url.$start_str.$temp_start.'">'.$maximum.'</a>'; + } + + $navbar.= ' | '; + // link on next page ? + if ($nb_element > $nb_element_page + and $start + $nb_element_page < $nb_element) + { + $next = $start + $nb_element_page; + + $navbar.= + '<a href="'.$url.$start_str.$next.'" rel="next">' + .l10n('next_page') + .'</a>'; + } + else + { + $navbar.= l10n('next_page'); + } + + $navbar.= ' | '; + // link to last page ? + if ($cur_page != $maximum) + { + $temp_start = ($maximum - 1) * $nb_element_page; + + $navbar.= + '<a href="'.$url.$start_str.$temp_start.'" rel="last">' + .l10n('last_page') + .'</a>'; + } + else + { + $navbar.= l10n('last_page'); + } + } + return $navbar; +} + +/** + * returns the list of categories as a HTML string + * + * categories string returned contains categories as given in the input + * array $cat_informations. $cat_informations array must be an array + * of array( id=>?, name=>?, permalink=>?). If url input parameter is null, + * returns only the categories name without links. + * + * @param array cat_informations + * @param string url + * @param boolean replace_space + * @return string + */ +function get_cat_display_name($cat_informations, + $url = '', + $replace_space = true) +{ + global $conf; + + $output = ''; + $is_first = true; + foreach ($cat_informations as $cat) + { + is_array($cat) or trigger_error( + 'get_cat_display_name wrong type for category ', E_USER_WARNING + ); + if ($is_first) + { + $is_first = false; + } + else + { + $output.= $conf['level_separator']; + } + + if ( !isset($url) ) + { + $output.= $cat['name']; + } + elseif ($url == '') + { + $output.= '<a href="' + .make_index_url( + array( + 'category' => $cat, + ) + ) + .'">'; + $output.= $cat['name'].'</a>'; + } + else + { + $output.= '<a href="'.PHPWG_ROOT_PATH.$url.$cat['id'].'">'; + $output.= $cat['name'].'</a>'; + } + } + if ($replace_space) + { + return replace_space($output); + } + else + { + return $output; + } +} + +/** + * returns the list of categories as a HTML string, with cache of names + * + * categories string returned contains categories as given in the input + * array $cat_informations. $uppercats is the list of category ids to + * display in the right order. If url input parameter is empty, returns only + * the categories name without links. + * + * @param string uppercats + * @param string url + * @param boolean replace_space + * @return string + */ +function get_cat_display_name_cache($uppercats, + $url = '', + $replace_space = true) +{ + global $cache, $conf; + + if (!isset($cache['cat_names'])) + { + $query = ' +SELECT id, name, permalink + FROM '.CATEGORIES_TABLE.' +;'; + $cache['cat_names'] = hash_from_query($query, 'id'); + } + + $output = ''; + $is_first = true; + foreach (explode(',', $uppercats) as $category_id) + { + $cat = $cache['cat_names'][$category_id]; + + if ($is_first) + { + $is_first = false; + } + else + { + $output.= $conf['level_separator']; + } + + if ( !isset($url) ) + { + $output.= $cat['name']; + } + elseif ($url == '') + { + $output.= ' +<a href="' + .make_index_url( + array( + 'category' => $cat, + ) + ) + .'">'.$cat['name'].'</a>'; + } + else + { + $output.= ' +<a href="'.PHPWG_ROOT_PATH.$url.$category_id.'">'.$cat['name'].'</a>'; + } + } + if ($replace_space) + { + return replace_space($output); + } + else + { + return $output; + } +} + +/** + * returns the HTML code for a category item in the menu (for the main page) + * + * HTML code generated uses logical list tags ul and each category is an + * item li. The paramter given is the category informations as an array, + * used keys are : id, name, nb_images, max_date_last, date_last + * count_images, count_categories + * + * @param array categories + * @return string + */ +function get_html_menu_category($categories, $selected_category) +{ + $ref_level = 0; + $level = 0; + + $menu = trigger_event('get_html_menu_category', '', + $categories, $selected_category); + if (strlen($menu)) + { + return $menu; + } + + foreach ($categories as $category) + { + $level = substr_count($category['global_rank'], '.') + 1; + if ($level > $ref_level) + { + $menu.= "\n<ul>"; + } + else if ($level == $ref_level) + { + $menu.= "\n</li>"; + } + else if ($level < $ref_level) + { + // we may have to close more than one level at the same time... + $menu.= "\n</li>"; + $menu.= str_repeat("\n</ul></li>",($ref_level-$level)); + } + $ref_level = $level; + + $menu.= "\n\n".'<li'; + if ($category['id'] == @$selected_category['id']) + { + $menu.= ' class="selected"'; + } + $menu.= '>'; + + $url = make_index_url( + array( + 'category' => $category + ) + ); + + $title = get_display_images_count + ( + $category['nb_images'], + $category['count_images'], + $category['count_categories'], + false, + ' / ' + ); + + $menu.= '<a href="'.$url.'"'; + if ($selected_category!=null + and $category['id'] == $selected_category['id_uppercat']) + { + $menu.= ' rel="up"'; + } + $menu.= ' title="'.$title.'">'.$category['name'].'</a>'; + + if ( $category['count_images']>0 ) + {// at least one direct or indirect image + $menu.= "\n".'<span class="'; + // at least one image in this category -> class menuInfoCat + $menu.= ($category['nb_images'] > 0 ? "menuInfoCat" + : "menuInfoCatByChild").'"'; + $menu.= ' title=" '.$title.'">'; + // show total number of images + $menu.= '['.$category['count_images'].']'; + $menu.= '</span>'; + } + $child_date_last = @$category['max_date_last']> @$category['date_last']; + $menu.= get_icon($category['max_date_last'], $child_date_last); + } + + $menu.= str_repeat("\n</li></ul>",($level)); + + return $menu; +} + +/** + * returns HTMLized comment contents retrieved from database + * + * newlines becomes br tags, _word_ becomes underline, /word/ becomes + * italic, *word* becomes bolded + * + * @param string content + * @return string + */ +function parse_comment_content($content) +{ + $pattern = '/(https?:\/\/\S*)/'; + $replacement = '<a href="$1" rel="nofollow">$1</a>'; + $content = preg_replace($pattern, $replacement, $content); + + $content = nl2br($content); + + // replace _word_ by an underlined word + $pattern = '/\b_(\S*)_\b/'; + $replacement = '<span style="text-decoration:underline;">$1</span>'; + $content = preg_replace($pattern, $replacement, $content); + + // replace *word* by a bolded word + $pattern = '/\b\*(\S*)\*\b/'; + $replacement = '<span style="font-weight:bold;">$1</span>'; + $content = preg_replace($pattern, $replacement, $content); + + // replace /word/ by an italic word + $pattern = "/\/(\S*)\/(\s)/"; + $replacement = '<span style="font-style:italic;">$1$2</span>'; + $content = preg_replace($pattern, $replacement, $content); + + $content = '<div>'.$content.'</div>'; + return $content; +} + +function get_cat_display_name_from_id($cat_id, + $url = '', + $replace_space = true) +{ + $cat_info = get_cat_info($cat_id); + return get_cat_display_name($cat_info['upper_names'], $url, $replace_space); +} + +/** + * Returns an HTML list of tags. It can be a multi select field or a list of + * checkboxes. + * + * @param string HTML field name + * @param array selected tag ids + * @return array + */ +function get_html_tag_selection( + $tags, + $fieldname, + $selecteds = array(), + $forbidden_categories = null + ) +{ + global $conf; + + if (count ($tags) == 0 ) + { + return ''; + } + $output = '<ul class="tagSelection">'; + foreach ($tags as $tag) + { + $output.= + '<li>' + .'<label>' + .'<input type="checkbox" name="'.$fieldname.'[]"' + .' value="'.$tag['id'].'"' + ; + + if (in_array($tag['id'], $selecteds)) + { + $output.= ' checked="checked"'; + } + + $output.= + ' />' + .' '. $tag['name'] + .'</label>' + .'</li>' + ."\n" + ; + } + $output.= '</ul>'; + + return $output; +} + +function name_compare($a, $b) +{ + return strcmp(strtolower($a['name']), strtolower($b['name'])); +} + +/** + * exits the current script (either exit or redirect) + */ +function access_denied() +{ + global $user; + + $login_url = + get_root_url().'identification.php?redirect=' + .urlencode(urlencode($_SERVER['REQUEST_URI'])); + + if ( isset($user) and !is_a_guest() ) + { + echo '<div style="text-align:center;">'.l10n('access_forbiden').'<br />'; + echo '<a href="'.get_root_url().'identification.php">'.l10n('identification').'</a> '; + echo '<a href="'.make_index_url().'">'.l10n('home').'</a></div>'; + exit(); + } + else + { + set_status_header(401); + redirect_html($login_url); + } +} + +/** + * exits the current script with 403 code + * @param string msg a message to display + * @param string alternate_url redirect to this url + */ +function page_forbidden($msg, $alternate_url=null) +{ + set_status_header(403); + if ($alternate_url==null) + $alternate_url = make_index_url(); + redirect_html( $alternate_url, + '<div style="text-align:left; margin-left:5em;margin-bottom:5em;"> +<h1 style="text-align:left; font-size:36px;">Forbidden</h1><br/>' +.$msg.'</div>', + 5 ); +} + +/** + * exits the current script with 400 code + * @param string msg a message to display + * @param string alternate_url redirect to this url + */ +function bad_request($msg, $alternate_url=null) +{ + set_status_header(400); + if ($alternate_url==null) + $alternate_url = make_index_url(); + redirect_html( $alternate_url, + '<div style="text-align:left; margin-left:5em;margin-bottom:5em;"> +<h1 style="text-align:left; font-size:36px;">Bad request</h1><br/>' +.$msg.'</div>', + 5 ); +} + +/** + * exits the current script with 404 code when a page cannot be found + * @param string msg a message to display + * @param string alternate_url redirect to this url + */ +function page_not_found($msg, $alternate_url=null) +{ + set_status_header(404); + if ($alternate_url==null) + $alternate_url = make_index_url(); + redirect_html( $alternate_url, + '<div style="text-align:left; margin-left:5em;margin-bottom:5em;"> +<h1 style="text-align:left; font-size:36px;">Page not found</h1><br/>' +.$msg.'</div>', + 5 ); +} + +/* returns the title to be displayed above thumbnails on tag page + */ +function get_tags_content_title() +{ + global $page; + $title = count($page['tags']) > 1 ? l10n('Tags') : l10n('Tag'); + $title.= ' '; + + for ($i=0; $i<count($page['tags']); $i++) + { + $title.= $i>0 ? ' + ' : ''; + + $title.= + '<a href="' + .make_index_url( + array( + 'tags' => array( $page['tags'][$i] ) + ) + ) + .'" title="' + .l10n('See elements linked to this tag only') + .'">' + .$page['tags'][$i]['name'] + .'</a>'; + + if ( count($page['tags'])>2 ) + { + $other_tags = $page['tags']; + unset ( $other_tags[$i] ); + $title.= + '<a href="' + .make_index_url( + array( + 'tags' => $other_tags + ) + ) + .'" style="border:none;" title="' + .l10n('remove this tag') + .'"><img src="' + .get_root_url().get_themeconf('icon_dir').'/remove_s.png' + .'" alt="x" style="vertical-align:bottom;" class="button"/>' + .'</a>'; + } + + } + return $title; +} + +/** + Sets the http status header (200,401,...) + */ +function set_status_header($code, $text='') +{ + if (empty($text)) + { + switch ($code) + { + case 200: $text='OK';break; + case 301: $text='Moved permanently';break; + case 302: $text='Moved temporarily';break; + case 304: $text='Not modified';break; + case 400: $text='Bad request';break; + case 401: $text='Authorization required';break; + case 403: $text='Forbidden';break; + case 404: $text='Not found';break; + case 500: $text='Server error';break; + case 503: $text='Service unavailable';break; + } + } + $protocol = $_SERVER["SERVER_PROTOCOL"]; + if ( ('HTTP/1.1' != $protocol) && ('HTTP/1.0' != $protocol) ) + $protocol = 'HTTP/1.0'; + + if ( version_compare( phpversion(), '4.3.0', '>=' ) ) + { + header( "$protocol $code $text", true, $code ); + } + else + { + header( "$protocol $code $text" ); + } + trigger_action('set_status_header', $code, $text); +} + +/** returns the category comment for rendering in html. + * this is an event handler. don't call directly + */ +function render_category_description($desc) +{ + global $conf; + if ( !( $conf['allow_html_descriptions'] and + preg_match('/<(div|br|img|script).*>/i', $desc) ) ) + { + $desc = nl2br($desc); + } + return $desc; +} + +/** returns the category comment for rendering in html textual mode (subcatify) + * this is an event handler. don't call directly + */ +function render_category_literal_description($desc) +{ + return strip_tags($desc, '<span><p><a><br><b><i><small><big><strong><em>'); +} + +/** returns the argument_ids array with new sequenced keys based on related + * names. Sequence is not case sensitive. + * Warning: By definition, this function breaks original keys + */ +function order_by_name($element_ids,$name) +{ + $ordered_element_ids = array(); + foreach ($element_ids as $k_id => $element_id) + { + $key = strtolower($name[$element_id]) .'-'. $name[$element_id] .'-'. $k_id; + $ordered_element_ids[$key] = $element_id; + } + ksort($ordered_element_ids); + return $ordered_element_ids; +} + +?> diff --git a/BSF/include/functions_mail.inc.php b/BSF/include/functions_mail.inc.php new file mode 100644 index 000000000..9e7f9024d --- /dev/null +++ b/BSF/include/functions_mail.inc.php @@ -0,0 +1,822 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// +-----------------------------------------------------------------------+ +// | functions | +// +-----------------------------------------------------------------------+ + + +/** + * Encodes a string using Q form if required (RFC2045) + * mail headers MUST contain only US-ASCII characters + */ +function encode_mime_header($str) +{ + $x = preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); + if ($x==0) + { + return $str; + } + // Replace every high ascii, control =, ? and _ characters + $str = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e', + "'='.sprintf('%02X', ord('\\1'))", $str); + + // Replace every spaces to _ (more readable than =20) + $str = str_replace(" ", "_", $str); + + global $lang_info; + return '=?'.get_pwg_charset().'?Q?'.$str.'?='; +} + +/* + * Returns the name of the mail sender : + * + * @return string + */ +function get_mail_sender_name() +{ + global $conf; + + return (empty($conf['mail_sender_name']) ? $conf['gallery_title'] : $conf['mail_sender_name']); +} + +/* + * Returns an array of mail configuration parameters : + * + * - mail_options: see $conf['mail_options'] + * - send_bcc_mail_webmaster: see $conf['send_bcc_mail_webmaster'] + * - email_webmaster: mail corresponding to $conf['webmaster_id'] + * - formated_email_webmaster: the name of webmaster is $conf['gallery_title'] + * - text_footer: Piwigo and version + * + * @return array + */ +function get_mail_configuration() +{ + global $conf; + + $conf_mail = array( + 'mail_options' => $conf['mail_options'], + 'send_bcc_mail_webmaster' => $conf['send_bcc_mail_webmaster'], + 'default_email_format' => $conf['default_email_format'], + 'use_smtp' => !empty($conf['smtp_host']), + 'smtp_host' => $conf['smtp_host'], + 'smtp_user' => $conf['smtp_user'], + 'smtp_password' => $conf['smtp_password'] + ); + + // we have webmaster id among user list, what's his email address ? + $conf_mail['email_webmaster'] = get_webmaster_mail_address(); + + // name of the webmaster is the title of the gallery + $conf_mail['formated_email_webmaster'] = + format_email(get_mail_sender_name(), $conf_mail['email_webmaster']); + + $conf_mail['boundary_key'] = generate_key(32); + + return $conf_mail; +} + +/** + * Returns an email address with an associated real name + * + * @param string name + * @param string email + */ +function format_email($name, $email) +{ + // Spring cleaning + $cvt_email = trim(preg_replace('#[\n\r]+#s', '', $email)); + $cvt_name = trim(preg_replace('#[\n\r]+#s', '', $name)); + + if ($cvt_name!="") + { + $cvt_name = encode_mime_header( + '"' + .addcslashes($cvt_name,'"') + .'"'); + $cvt_name .= ' '; + } + + if (strpos($cvt_email, '<') === false) + { + return $cvt_name.'<'.$cvt_email.'>'; + } + else + { + return $cvt_name.$cvt_email; + } +} + +/** + * Returns an email address list with minimal email string + * + * @param string with email list (email separated by comma) + */ +function get_strict_email_list($email_list) +{ + $result = array(); + $list = explode(',', $email_list); + foreach ($list as $email) + { + if (strpos($email, '<') !== false) + { + $email = preg_replace('/.*<(.*)>.*/i', '$1', $email); + } + $result[] = trim($email); + } + + return implode(',', $result); +} + +/** + * Returns an completed array template/theme + * completed with get_default_template() + * + * @params: + * - args: incompleted array of template/theme + * o template: template to use [default get_default_template()] + * o theme: template to use [default get_default_template()] + */ +function get_array_template_theme($args = array()) +{ + global $conf; + + $res = array(); + + if (empty($args['template']) or empty($args['theme'])) + { + list($res['template'], $res['theme']) = explode('/', get_default_template()); + } + + if (!empty($args['template'])) + { + $res['template'] = $args['template']; + } + + if (!empty($args['theme'])) + { + $res['theme'] = $args['theme']; + } + + return $res; +} + +/** + * Return an new mail template + * + * @params: + * - email_format: mail format + * - args: function params of mail function: + * o template: template to use [default get_default_template()] + * o theme: template to use [default get_default_template()] + */ +function & get_mail_template($email_format, $args = array()) +{ + $args = get_array_template_theme($args); + + $mail_template = new Template(PHPWG_ROOT_PATH.'template/'.$args['template'], $args['theme']); + $mail_template->set_template_dir(PHPWG_ROOT_PATH.'template/'.$args['template'].'/mail/'.$email_format); + return $mail_template; +} + +/** + * Return string email format (html or not) + * + * @param string format + */ +function get_str_email_format($is_html) +{ + return ($is_html ? 'text/html' : 'text/plain'); +} + +/* + * Switch language to param language + * All entries are push on language stack + * + * @param string language + */ +function switch_lang_to($language) +{ + global $switch_lang, $user, $lang, $lang_info; + + if (count($switch_lang['stack']) == 0) + { + $prev_language = $user['language']; + } + else + { + $prev_language = end($switch_lang['stack']); + } + + $switch_lang['stack'][] = $language; + + if ($prev_language != $language) + { + if (!isset($switch_lang['language'][$prev_language])) + { + $switch_lang[$prev_language]['lang_info'] = $lang_info; + $switch_lang[$prev_language]['lang'] = $lang; + } + + if (!isset($switch_lang['language'][$language])) + { + // Re-Init language arrays + $lang_info = array(); + $lang = array(); + + // language files + load_language('common.lang', '', $language); + // No test admin because script is checked admin (user selected no) + // Translations are in admin file too + load_language('admin.lang', '', $language); + trigger_action('loading_lang'); + load_language('local.lang', '', $language); + + $switch_lang[$language]['lang_info'] = $lang_info; + $switch_lang[$language]['lang'] = $lang; + } + else + { + $lang_info = $switch_lang[$language]['lang_info']; + $lang = $switch_lang[$language]['lang']; + } + + $user['language'] = $language; + } +} + +/* + * Switch back language pushed with switch_lang_to function + * + * @param: none + */ +function switch_lang_back() +{ + global $switch_lang, $user, $lang, $lang_info; + + $last_language = array_pop($switch_lang['stack']); + + if (count($switch_lang['stack']) > 0) + { + $language = end($switch_lang['stack']); + } + else + { + $language = $user['language']; + } + + if ($last_language != $language) + { + if (!isset($switch_lang['language'][$language])) + { + $lang_info = $switch_lang[$language]['lang_info']; + $lang = $switch_lang[$language]['lang']; + } + $user['language'] = $language; + } +} + +/** + * Returns email of all administrator + * + * @return string + */ +/* + * send en notification email to all administrators + * if a administrator is doing action, + * he's be removed to email list + * + * @param: + * - keyargs_subject: mail subject on l10n_args format + * - keyargs_content: mail content on l10n_args format + * + * @return boolean (Ok or not) + */ +function pwg_mail_notification_admins($keyargs_subject, $keyargs_content) +{ + // Check arguments + if + ( + empty($keyargs_subject) or + empty($keyargs_content) + ) + { + return false; + } + + global $conf, $user; + $return = true; + + $admins = array(); + + $query = ' +select + U.'.$conf['user_fields']['username'].' as username, + U.'.$conf['user_fields']['email'].' as mail_address +from + '.USERS_TABLE.' as U, + '.USER_INFOS_TABLE.' as I +where + I.user_id = U.'.$conf['user_fields']['id'].' and + I.status in (\'webmaster\', \'admin\') and + I.adviser = \'false\' and + '.$conf['user_fields']['email'].' is not null and + I.user_id <> '.$user['id'].' +order by + username +'; + + $datas = pwg_query($query); + if (!empty($datas)) + { + while ($admin = mysql_fetch_array($datas)) + { + if (!empty($admin['mail_address'])) + { + array_push($admins, format_email($admin['username'], $admin['mail_address'])); + } + } + } + + if (count($admins) > 0) + { + $keyargs_content_admin_info = array + ( + get_l10n_args('Connected user: %s', $user['username']), + get_l10n_args('IP: %s', $_SERVER['REMOTE_ADDR']), + get_l10n_args('Browser: %s', $_SERVER['HTTP_USER_AGENT']) + ); + + switch_lang_to(get_default_language()); + + $return = pwg_mail + ( + '', + array + ( + 'Bcc' => $admins, + 'subject' => '['.$conf['gallery_title'].'] '.l10n_args($keyargs_subject), + 'content' => + l10n_args($keyargs_content)."\n\n" + .l10n_args($keyargs_content_admin_info)."\n", + 'content_format' => 'text/plain' + ) + ) and $return; + + switch_lang_back(); + } + + return $return; +} + +/* + * send en email to user's group + * + * @param: + * - group_id: mail are sent to group with this Id + * - email_format: mail format + * - keyargs_subject: mail subject on l10n_args format + * - dirname: short name of directory including template + * - tpl_shortname: short template name without extension + * - assign_vars: array used to assign_vars to mail template + * - language_selected: send mail only to user with this selected language + * + * @return boolean (Ok or not) + */ +function pwg_mail_group( + $group_id, $email_format, $keyargs_subject, + $dirname, $tpl_shortname, + $assign_vars = array(), $language_selected = '') +{ + // Check arguments + if + ( + empty($group_id) or + empty($email_format) or + empty($keyargs_subject) or + empty($tpl_shortname) + ) + { + return false; + } + + global $conf; + $return = true; + + $query = ' +SELECT + distinct language, template +FROM + '.USER_GROUP_TABLE.' as ug + INNER JOIN '.USERS_TABLE.' as u ON '.$conf['user_fields']['id'].' = ug.user_id + INNER JOIN '.USER_INFOS_TABLE.' as ui ON ui.user_id = ug.user_id +WHERE + '.$conf['user_fields']['email'].' IS NOT NULL + AND group_id = '.$group_id; + + if (!empty($language_selected)) + { + $query .= ' + AND language = \''.$language_selected.'\''; + } + + $query .= ' +;'; + + $result = pwg_query($query); + + if (mysql_num_rows($result) > 0) + { + $list = array(); + while ($row = mysql_fetch_array($result)) + { + $row['template_theme'] = $row['template']; + list($row['template'], $row['theme']) = explode('/', $row['template_theme']); + $list[] = $row; + } + + foreach ($list as $elem) + { + $query = ' +SELECT + u.'.$conf['user_fields']['username'].' as username, + u.'.$conf['user_fields']['email'].' as mail_address +FROM + '.USER_GROUP_TABLE.' as ug + INNER JOIN '.USERS_TABLE.' as u ON '.$conf['user_fields']['id'].' = ug.user_id + INNER JOIN '.USER_INFOS_TABLE.' as ui ON ui.user_id = ug.user_id +WHERE + '.$conf['user_fields']['email'].' IS NOT NULL + AND group_id = '.$group_id.' + AND language = \''.$elem['language'].'\' + AND template = \''.$elem['template_theme'].'\' +;'; + + $result = pwg_query($query); + + if (mysql_num_rows($result) > 0) + { + $Bcc = array(); + while ($row = mysql_fetch_array($result)) + { + if (!empty($row['mail_address'])) + { + array_push($Bcc, format_email($row['username'], $row['mail_address'])); + } + } + + if (count($Bcc) > 0) + { + switch_lang_to($elem['language']); + + $mail_template = get_mail_template($email_format, $elem); + $mail_template->set_filename($tpl_shortname, + (empty($dirname) ? '' : $dirname.'/').$tpl_shortname.'.tpl'); + + $mail_template->assign( + trigger_event('mail_group_assign_vars', $assign_vars)); + + $return = pwg_mail + ( + '', + array + ( + 'Bcc' => $Bcc, + 'subject' => l10n_args($keyargs_subject), + 'email_format' => $email_format, + 'content' => $mail_template->parse($tpl_shortname, true), + 'content_format' => $email_format, + 'template' => $elem['template'], + 'theme' => $elem['theme'] + ) + ) and $return; + + switch_lang_back(); + } + } + } + } + + return $return; +} + +/* + * sends an email, using Piwigo specific informations + * + * @param: + * - to: receiver(s) of the mail (list separated by comma). + * - args: function params of mail function: + * o from: sender [default value webmaster email] + * o Cc: array of carbon copy receivers of the mail. [default value empty] + * o Bcc: array of blind carbon copy receivers of the mail. [default value empty] + * o subject [default value 'Piwigo'] + * o content: content of mail [default value ''] + * o content_format: format of mail content [default value 'text/plain'] + * o email_format: global mail format [default value $conf_mail['default_email_format']] + * o template: template to use [default get_default_template()] + * o theme: template to use [default get_default_template()] + * + * @return boolean (Ok or not) + */ +function pwg_mail($to, $args = array()) +{ + global $conf, $conf_mail, $lang_info, $page; + + if (empty($to) and empty($args['Cc']) and empty($args['Bcc'])) + { + return true; + } + + if (!isset($conf_mail)) + { + $conf_mail = get_mail_configuration(); + } + + if (empty($args['email_format'])) + { + $args['email_format'] = $conf_mail['default_email_format']; + } + + // Compute root_path in order have complete path + if ($args['email_format'] == 'text/html') + { + set_make_full_url(); + } + + if (empty($args['from'])) + { + $args['from'] = $conf_mail['formated_email_webmaster']; + } + else + { + $args['from'] = format_email('', $args['from']); + } + + if (empty($args['subject'])) + { + $args['subject'] = 'Piwigo'; + } + // Spring cleaning + $cvt_subject = trim(preg_replace('#[\n\r]+#s', '', $args['subject'])); + // Ascii convertion + $cvt_subject = encode_mime_header($cvt_subject); + + if (!isset($args['content'])) + { + $args['content'] = ''; + } + + if (empty($args['content_format'])) + { + $args['content_format'] = 'text/plain'; + } + + if ($conf_mail['send_bcc_mail_webmaster']) + { + $args['Bcc'][] = $conf_mail['formated_email_webmaster']; + } + + if (($args['content_format'] == 'text/html') and ($args['email_format'] == 'text/plain')) + { + // Todo find function to convert html text to plain text + return false; + } + + $args = array_merge($args, get_array_template_theme($args)); + + $headers = 'From: '.$args['from']."\n"; + $headers.= 'Reply-To: '.$args['from']."\n"; + if (empty($to)) + { + $headers.= 'To: undisclosed-recipients: ;'."\n"; + } + else + { + $headers.= 'To: '.$to."\n"; + } + + if (!empty($args['Cc'])) + { + $headers.= 'Cc: '.implode(',', $args['Cc'])."\n"; + } + + if (!empty($args['Bcc'])) + { + $headers.= 'Bcc: '.implode(',', $args['Bcc'])."\n"; + } + + $headers.= 'Content-Type: multipart/alternative;'."\n"; + $headers.= ' boundary="---='.$conf_mail['boundary_key'].'";'."\n"; + $headers.= ' reply-type=original'."\n"; + $headers.= 'MIME-Version: 1.0'."\n"; + $headers.= 'X-Mailer: Piwigo Mailer'."\n"; + + $content = ''; + + // key compose of indexes witch allow ti cache mail data + $cache_key = $args['email_format'].'-'.$lang_info['code'].'-'.$args['template'].'-'.$args['theme']; + + if (!isset($conf_mail[$cache_key])) + { + if (!isset($mail_template)) + { + $mail_template = get_mail_template($args['email_format']); + } + + $mail_template->set_filename('mail_header', 'header.tpl'); + $mail_template->set_filename('mail_footer', 'footer.tpl'); + + $mail_template->assign( + array( + //Header + 'BOUNDARY_KEY' => $conf_mail['boundary_key'], + 'CONTENT_TYPE' => $args['email_format'], + 'CONTENT_ENCODING' => get_pwg_charset(), + 'LANG' => $lang_info['code'], + 'DIR' => $lang_info['direction'], + + // Footer + 'GALLERY_URL' => + isset($page['gallery_url']) ? + $page['gallery_url'] : $conf['gallery_url'], + 'GALLERY_TITLE' => + isset($page['gallery_title']) ? + $page['gallery_title'] : $conf['gallery_title'], + 'VERSION' => $conf['show_version'] ? PHPWG_VERSION : '', + 'PHPWG_URL' => PHPWG_URL, + + 'TITLE_MAIL' => urlencode(l10n('title_send_mail')), + 'MAIL' => get_webmaster_mail_address() + )); + + if ($args['email_format'] == 'text/html') + { + if (is_file($mail_template->get_template_dir().'/global-mail-css.tpl')) + { + $mail_template->set_filename('css', 'global-mail-css.tpl'); + $mail_template->assign_var_from_handle('GLOBAL_MAIL_CSS', 'css'); + } + + $root_abs_path = dirname(dirname(__FILE__)); + + $file = $root_abs_path.'/template/'.$args['template'].'/theme/'.$args['theme'].'/mail-css.tpl'; + if (is_file($file)) + { + $mail_template->set_filename('css', $file); + $mail_template->assign_var_from_handle('MAIL_CSS', 'css'); + } + + $file = $root_abs_path.'/template-common/local-mail-css.tpl'; + if (is_file($file)) + { + $mail_template->set_filename('css', $file); + $mail_template->assign_var_from_handle('LOCAL_MAIL_CSS', 'css'); + } + } + + // what are displayed on the header of each mail ? + $conf_mail[$cache_key]['header'] = + $mail_template->parse('mail_header', true); + + // what are displayed on the footer of each mail ? + $conf_mail[$cache_key]['footer'] = + $mail_template->parse('mail_footer', true); + } + + // Header + $content.= $conf_mail[$cache_key]['header']; + + // Content + if (($args['content_format'] == 'text/plain') and ($args['email_format'] == 'text/html')) + { + $content.= '<p>'. + nl2br( + preg_replace("/(http:\/\/)([^\s,]*)/i", + "<a href='$1$2'>$1$2</a>", + htmlspecialchars($args['content']))). + '</p>'; + } + else + { + $content.= $args['content']; + } + + // Footer + $content.= $conf_mail[$cache_key]['footer']; + + // Close boundary + $content.= "\n".'-----='.$conf_mail['boundary_key'].'--'."\n"; + + // Undo Compute root_path in order have complete path + if ($args['email_format'] == 'text/html') + { + unset_make_full_url(); + } + + return + trigger_event('send_mail', + false, /* Result */ + trigger_event('send_mail_to', get_strict_email_list($to)), + trigger_event('send_mail_subject', $cvt_subject), + trigger_event('send_mail_content', $content), + trigger_event('send_mail_headers', $headers), + $args + ); +} + +/* + * pwg sendmail + * + * @param: + * - result of other sendmail + * - to: Receiver or receiver(s) of the mail. + * - subject [default value 'Piwigo'] + * - content: content of mail + * - headers: headers of mail + * + * @return boolean (Ok or not) + */ +function pwg_send_mail($result, $to, $subject, $content, $headers) +{ + if (!$result) + { + global $conf_mail; + + if ($conf_mail['use_smtp']) + { + include_once( PHPWG_ROOT_PATH.'include/class_smtp_mail.inc.php' ); + $smtp_mail = new smtp_mail( + $conf_mail['smtp_host'], $conf_mail['smtp_user'], $conf_mail['smtp_password'], + $conf_mail['email_webmaster']); + return $smtp_mail->mail($to, $subject, $content, $headers); + } + else + { + if ($conf_mail['mail_options']) + { + $options = '-f '.$conf_mail['email_webmaster']; + return mail($to, $subject, $content, $headers, $options); + } + else + { + return mail($to, $subject, $content, $headers); + } + } + } + else + { + return $result; + } +} + +/*Testing block*/ +/*function pwg_send_mail_test($result, $to, $subject, $content, $headers, $args) +{ + global $conf, $user, $lang_info; + $dir = $conf['local_data_dir'].'/tmp'; + @mkdir( $dir ); + $filename = $dir.'/mail.'.$user['username'].'.'.$lang_info['code'].'.'.$args['template'].'.'.$args['theme']; + if ($args['content_format'] == 'text/plain') + { + $filename .= '.txt'; + } + else + { + $filename .= '.html'; + } + $file = fopen($filename, 'w+'); + fwrite($file, $to ."\n"); + fwrite($file, $subject ."\n"); + fwrite($file, $headers); + fwrite($file, $content); + fclose($file); + return $result; +} +add_event_handler('send_mail', 'pwg_send_mail_test', EVENT_HANDLER_PRIORITY_NEUTRAL+10, 6);*/ + + +add_event_handler('send_mail', 'pwg_send_mail', EVENT_HANDLER_PRIORITY_NEUTRAL, 5); +trigger_action('functions_mail_included'); + +?> diff --git a/BSF/include/functions_metadata.inc.php b/BSF/include/functions_metadata.inc.php new file mode 100644 index 000000000..df89eea9c --- /dev/null +++ b/BSF/include/functions_metadata.inc.php @@ -0,0 +1,142 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * returns informations from IPTC metadata, mapping is done at the beginning + * of the function + * + * @param string $filename + * @return array + */ +function get_iptc_data($filename, $map) +{ + $result = array(); + + $imginfo = array(); + if (false == @getimagesize($filename, $imginfo) ) + { + return $result; + } + + if (isset($imginfo['APP13'])) + { + $iptc = iptcparse($imginfo['APP13']); + if (is_array($iptc)) + { + $rmap = array_flip($map); + foreach (array_keys($rmap) as $iptc_key) + { + if (isset($iptc[$iptc_key][0])) + { + if ($iptc_key == '2#025') + { + $value = implode(',', + array_map('clean_iptc_value',$iptc[$iptc_key])); + } + else + { + $value = clean_iptc_value($iptc[$iptc_key][0]); + } + + foreach (array_keys($map, $iptc_key) as $pwg_key) + { + $result[$pwg_key] = $value; + } + } + } + } + } + return $result; +} + +/** + * return a cleaned IPTC value + * + * @param string value + * @return string + */ +function clean_iptc_value($value) +{ + // strip leading zeros (weird Kodak Scanner software) + while ( isset($value[0]) and $value[0] == chr(0)) + { + $value = substr($value, 1); + } + // remove binary nulls + $value = str_replace(chr(0x00), ' ', $value); + + if ( preg_match('/[\x80-\xff]/', $value) ) + { + // apparently mac uses some MacRoman crap encoding. I don't know + // how to detect it so a plugin should do the trick. + $value = trigger_event('clean_iptc_value', $value); + $is_utf8 = seems_utf8($value); + $value = convert_charset( $value, + $is_utf8 ? 'utf-8' : 'iso-8859-1', + get_pwg_charset() ); + } + return $value; +} + +/** + * returns informations from EXIF metadata, mapping is done at the beginning + * of the function + * + * @param string $filename + * @return array + */ +function get_exif_data($filename, $map) +{ + $result = array(); + + if (!function_exists('read_exif_data')) + { + die('Exif extension not available, admin should disable exif use'); + } + + // Read EXIF data + if ($exif = @read_exif_data($filename)) + { + foreach ($map as $key => $field) + { + if (strpos($field, ';') === false) + { + if (isset($exif[$field])) + { + $result[$key] = $exif[$field]; + } + } + else + { + $tokens = explode(';', $field); + if (isset($exif[$tokens[0]][$tokens[1]])) + { + $result[$key] = $exif[$tokens[0]][$tokens[1]]; + } + } + } + } + + return $result; +} +?>
\ No newline at end of file diff --git a/BSF/include/functions_notification.inc.php b/BSF/include/functions_notification.inc.php new file mode 100644 index 000000000..259a34613 --- /dev/null +++ b/BSF/include/functions_notification.inc.php @@ -0,0 +1,608 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// +-----------------------------------------------------------------------+ +// | functions | +// +-----------------------------------------------------------------------+ + +/* + * get standard sql where in order to + * restict an filter caregories and images + * + * IMAGE_CATEGORY_TABLE muste named ic in the query + * + * @param none + * + * @return string sql where + */ +function get_std_sql_where_restrict_filter($prefix_condition, $force_one_condition = false) +{ + return get_sql_condition_FandF + ( + array + ( + 'forbidden_categories' => 'ic.category_id', + 'visible_categories' => 'ic.category_id', + 'visible_images' => 'ic.image_id' + ), + $prefix_condition, + $force_one_condition + ); +} + +/* + * Execute custom notification query + * + * @param string action ('count' or 'info') + * @param string type of query ('new_comments', 'unvalidated_comments', 'new_elements', 'updated_categories', 'new_users', 'waiting_elements') + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * + * @return integer for action count + * array for info + */ +function custom_notification_query($action, $type, $start, $end) +{ + global $user; + + switch($type) + { + case 'new_comments': + $query = ' + FROM '.COMMENTS_TABLE.' AS c + , '.IMAGE_CATEGORY_TABLE.' AS ic + WHERE c.image_id = ic.image_id + AND c.validation_date > \''.$start.'\' + AND c.validation_date <= \''.$end.'\' + '.get_std_sql_where_restrict_filter('AND').' +;'; + break; + case 'unvalidated_comments': + $query = ' + FROM '.COMMENTS_TABLE.' + WHERE date> \''.$start.'\' AND date <= \''.$end.'\' + AND validated = \'false\' +;'; + break; + case 'new_elements': + $query = ' + FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON image_id = id + WHERE date_available > \''.$start.'\' + AND date_available <= \''.$end.'\' + '.get_std_sql_where_restrict_filter('AND').' +;'; + break; + case 'updated_categories': + $query = ' + FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON image_id = id + WHERE date_available > \''.$start.'\' + AND date_available <= \''.$end.'\' + '.get_std_sql_where_restrict_filter('AND').' +;'; + break; + case 'new_users': + $query = ' + FROM '.USER_INFOS_TABLE.' + WHERE registration_date > \''.$start.'\' + AND registration_date <= \''.$end.'\' +;'; + break; + case 'waiting_elements': + $query = ' + FROM '.WAITING_TABLE.' + WHERE validated = \'false\' +;'; + break; + default: + // stop this function and return nothing + return; + break; + } + + switch($action) + { + case 'count': + switch($type) + { + case 'new_comments': + $field_id = 'c.id'; + break; + case 'unvalidated_comments': + $field_id = 'id'; + break; + case 'new_elements': + $field_id = 'image_id'; + break; + case 'updated_categories': + $field_id = 'category_id'; + break; + case 'new_users': + $field_id = 'user_id'; + break; + case 'waiting_elements': + $field_id = 'id'; + break; + } + $query = 'SELECT count(distinct '.$field_id.') as CountId +'.$query; + list($count) = mysql_fetch_array(pwg_query($query)); + return $count; + + break; + case 'info': + switch($type) + { + case 'new_comments': + $fields = array('c.id'); + break; + case 'unvalidated_comments': + $fields = array('id'); + break; + case 'new_elements': + $fields = array('image_id'); + break; + case 'updated_categories': + $fields = array('category_id'); + break; + case 'new_users': + $fields = array('user_id'); + break; + case 'waiting_elements': + $fields = array('id'); + break; + } + + $query = 'SELECT distinct '.implode(', ', $fields).' +'.$query; + $result = pwg_query($query); + + $infos = array(); + + while ($row = mysql_fetch_array($result)) + { + array_push($infos, $row); + } + + return $infos; + + break; + } + + //return is done on previous switch($action) +} + +/** + * new comments between two dates, according to authorized categories + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @param string forbidden categories (comma separated) + * @return count comment ids + */ +function nb_new_comments($start, $end) +{ + return custom_notification_query('count', 'new_comments', $start, $end); +} + +/** + * new comments between two dates, according to authorized categories + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @param string forbidden categories (comma separated) + * @return array comment ids + */ +function new_comments($start, $end) +{ + return custom_notification_query('info', 'new_comments', $start, $end); +} + +/** + * unvalidated at a precise date + * + * Comments that are registered and not validated yet on a precise date + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @return count comment ids + */ +function nb_unvalidated_comments($start, $end) +{ + return custom_notification_query('count', 'unvalidated_comments', $start, $end); +} + + +/** + * new elements between two dates, according to authorized categories + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @param string forbidden categories (comma separated) + * @return count element ids + */ +function nb_new_elements($start, $end) +{ + return custom_notification_query('count', 'new_elements', $start, $end); +} + +/** + * new elements between two dates, according to authorized categories + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @param string forbidden categories (comma separated) + * @return array element ids + */ +function new_elements($start, $end) +{ + return custom_notification_query('info', 'new_elements', $start, $end); +} + +/** + * updated categories between two dates, according to authorized categories + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @param string forbidden categories (comma separated) + * @return count element ids + */ +function nb_updated_categories($start, $end) +{ + return custom_notification_query('count', 'updated_categories', $start, $end); +} + +/** + * updated categories between two dates, according to authorized categories + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @param string forbidden categories (comma separated) + * @return array element ids + */ +function updated_categories($start, $end) +{ + return custom_notification_query('info', 'updated_categories', $start, $end); +} + +/** + * new registered users between two dates + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @return count user ids + */ +function nb_new_users($start, $end) +{ + return custom_notification_query('count', 'new_users', $start, $end); +} + +/** + * new registered users between two dates + * + * @param string start (mysql datetime format) + * @param string end (mysql datetime format) + * @return array user ids + */ +function new_users($start, $end) +{ + return custom_notification_query('info', 'new_users', $start, $end); +} + +/** + * currently waiting pictures + * + * @return count waiting ids + */ +function nb_waiting_elements() +{ + return custom_notification_query('count', 'waiting_elements', '', ''); +} + +/** + * currently waiting pictures + * + * @return array waiting ids + */ +function waiting_elements() +{ + return custom_notification_query('info', 'waiting_elements', $start, $end); +} + +/** + * There are new between two dates ? + * + * Informations : number of new comments, number of new elements, number of + * updated categories. Administrators are also informed about : number of + * unvalidated comments, number of new users (TODO : number of unvalidated + * elements) + * + * @param string start date (mysql datetime format) + * @param string end date (mysql datetime format) + * + * @return boolean : true if exist news else false + */ +function news_exists($start, $end) +{ + return ( + (nb_new_comments($start, $end) > 0) or + (nb_new_elements($start, $end) > 0) or + (nb_updated_categories($start, $end) > 0) or + ((is_admin()) and (nb_unvalidated_comments($start, $end) > 0)) or + ((is_admin()) and (nb_new_users($start, $end) > 0)) or + ((is_admin()) and (nb_waiting_elements() > 0)) + ); +} + +/** + * Formats a news line and adds it to the array (e.g. '5 new elements') + */ +function add_news_line(&$news, $count, $singular_fmt_key, $plural_fmt_key, $url='', $add_url=false) +{ + if ($count > 0) + { + $line = l10n_dec($singular_fmt_key, $plural_fmt_key, $count); + if ($add_url and !empty($url) ) + { + $line = '<a href="'.$url.'">'.$line.'</a>'; + } + array_push($news, $line); + } +} + +/** + * What's new between two dates ? + * + * Informations : number of new comments, number of new elements, number of + * updated categories. Administrators are also informed about : number of + * unvalidated comments, number of new users (TODO : number of unvalidated + * elements) + * + * @param string start date (mysql datetime format) + * @param string end date (mysql datetime format) + * @param bool exclude_img_cats if true, no info about new images/categories + * @param bool add_url add html A link around news + * + * @return array of news + */ +function news($start, $end, $exclude_img_cats=false, $add_url=false) +{ + $news = array(); + + if (!$exclude_img_cats) + { + add_news_line( $news, + nb_new_elements($start, $end), '%d new element', '%d new elements', + make_index_url(array('section'=>'recent_pics')), $add_url ); + } + + if (!$exclude_img_cats) + { + add_news_line( $news, + nb_updated_categories($start, $end), '%d category updated', '%d categories updated', + make_index_url(array('section'=>'recent_cats')), $add_url ); + } + + add_news_line( $news, + nb_new_comments($start, $end), '%d new comment', '%d new comments', + get_root_url().'comments.php', $add_url ); + + if (is_admin()) + { + add_news_line( $news, + nb_unvalidated_comments($start, $end), '%d comment to validate', '%d comments to validate', + get_root_url().'admin.php?page=comments', $add_url ); + + add_news_line( $news, + nb_new_users($start, $end), '%d new user', '%d new users', + get_root_url().'admin.php?page=user_list', $add_url ); + + add_news_line( $news, + nb_waiting_elements(), '%d waiting element', '%d waiting elements', + get_root_url().'admin.php?page=upload', $add_url ); + } + + return $news; +} + +/** + * returns information about recently published elements grouped by post date + * @param int max_dates maximum returned number of recent dates + * @param int max_elements maximum returned number of elements per date + * @param int max_cats maximum returned number of categories per date + */ +function get_recent_post_dates($max_dates, $max_elements, $max_cats) +{ + global $conf, $user; + + $where_sql = get_std_sql_where_restrict_filter('WHERE', true); + + $query = ' +SELECT date_available, + COUNT(DISTINCT id) nb_elements, + COUNT(DISTINCT category_id) nb_cats + FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id=image_id + '.$where_sql.' + GROUP BY date_available + ORDER BY date_available DESC + LIMIT 0,'.$max_dates.' +;'; + $result = pwg_query($query); + $dates = array(); + while ($row = mysql_fetch_assoc($result)) + { + array_push($dates, $row); + } + + for ($i=0; $i<count($dates); $i++) + { + if ($max_elements>0) + { // get some thumbnails ... + $query = ' +SELECT DISTINCT id, path, name, tn_ext, file + FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id=image_id + '.$where_sql.' + AND date_available="'.$dates[$i]['date_available'].'" + AND tn_ext IS NOT NULL + ORDER BY RAND(NOW()) + LIMIT 0,'.$max_elements.' +;'; + $dates[$i]['elements'] = array(); + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + array_push($dates[$i]['elements'], $row); + } + } + + if ($max_cats>0) + {// get some categories ... + $query = ' +SELECT DISTINCT c.uppercats, COUNT(DISTINCT i.id) img_count + FROM '.IMAGES_TABLE.' i INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON i.id=image_id + INNER JOIN '.CATEGORIES_TABLE.' c ON c.id=category_id + '.$where_sql.' + AND date_available="'.$dates[$i]['date_available'].'" + GROUP BY category_id + ORDER BY img_count DESC + LIMIT 0,'.$max_cats.' +;'; + $dates[$i]['categories'] = array(); + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + array_push($dates[$i]['categories'], $row); + } + } + } + return $dates; +} + +/* + Call function get_recent_post_dates but + the parameters to be passed to the function, as an indexed array. + +*/ +function get_recent_post_dates_array($args) +{ + return + get_recent_post_dates + ( + (empty($args['max_dates']) ? 3 : $args['max_dates']), + (empty($args['max_elements']) ? 3 : $args['max_elements']), + (empty($args['max_cats']) ? 3 : $args['max_cats']) + ); +} + + +/** + * returns html description about recently published elements grouped by post date + * @param $date_detail: selected date computed by get_recent_post_dates function + */ +function get_html_description_recent_post_date($date_detail) +{ + global $conf; + + $description = ''; + + $description .= + '<li>' + .l10n_dec('%d new element', '%d new elements', $date_detail['nb_elements']) + .' (' + .'<a href="'.make_index_url(array('section'=>'recent_pics')).'">' + .l10n('recent_pics_cat').'</a>' + .')' + .'</li><br/>'; + + foreach($date_detail['elements'] as $element) + { + $tn_src = get_thumbnail_url($element); + $description .= '<a href="'. + make_picture_url(array( + 'image_id' => $element['id'], + 'image_file' => $element['file'], + )) + .'"><img src="'.$tn_src.'"/></a>'; + } + $description .= '...<br/>'; + + $description .= + '<li>' + .l10n_dec('%d category updated', '%d categories updated', + $date_detail['nb_cats']) + .'</li>'; + + $description .= '<ul>'; + foreach($date_detail['categories'] as $cat) + { + $description .= + '<li>' + .get_cat_display_name_cache($cat['uppercats']) + .' ('. + l10n_dec('%d new element', + '%d new elements', $cat['img_count']).')' + .'</li>'; + } + $description .= '</ul>'; + + return $description; +} + +/** + * explodes a MySQL datetime format (2005-07-14 23:01:37) in fields "year", + * "month", "day", "hour", "minute", "second". + * + * @param string mysql datetime format + * @return array + */ +function explode_mysqldt($mysqldt) +{ + $date = array(); + list($date['year'], + $date['month'], + $date['day'], + $date['hour'], + $date['minute'], + $date['second']) + = preg_split('/[-: ]/', $mysqldt); + + return $date; +} + +/** + * returns title about recently published elements grouped by post date + * @param $date_detail: selected date computed by get_recent_post_dates function + */ +function get_title_recent_post_date($date_detail) +{ + global $lang; + + $date = $date_detail['date_available']; + $exploded_date = explode_mysqldt($date); + + $title = l10n_dec('%d new element', '%d new elements', $date_detail['nb_elements']); + $title .= ' ('.$lang['month'][(int)$exploded_date['month']].' '.$exploded_date['day'].')'; + + return $title; +} + +?>
\ No newline at end of file diff --git a/BSF/include/functions_picture.inc.php b/BSF/include/functions_picture.inc.php new file mode 100644 index 000000000..1b6403ff3 --- /dev/null +++ b/BSF/include/functions_picture.inc.php @@ -0,0 +1,330 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * @param element_info array containing element information from db; + * at least 'id', 'path' should be present + */ +function get_element_path($element_info) +{ + $path = get_element_location($element_info); + if ( !url_is_remote($path) ) + { + $path = PHPWG_ROOT_PATH.$path; + } + return $path; +} + +/* + * @param element_info array containing element information from db; + * at least 'id', 'path' should be present + */ +function get_element_url($element_info) +{ + $url = get_element_location($element_info); + if ( !url_is_remote($url) ) + { + $url = embellish_url(get_root_url().$url); + } + // plugins want another url ? + return trigger_event('get_element_url', $url, $element_info); +} + +/** + * Returns the relative path of the element with regards to to the root + * of PWG (not the current page). This function is not intended to be + * called directly from code. + * @param element_info array containing element information from db; + * at least 'id', 'path' should be present + */ +function get_element_location($element_info) +{ + // maybe a cached watermark ? + return trigger_event('get_element_location', + $element_info['path'], $element_info); +} + + +/** + * Returns the PATH to the image to be displayed in the picture page. If the + * element is not a picture, then the representative image or the default + * mime image. The path can be used in the php script, but not sent to the + * browser. + * @param element_info array containing element information from db; + * at least 'id', 'path', 'representative_ext' should be present + */ +function get_image_path($element_info) +{ + global $conf; + $ext = get_extension($element_info['path']); + if (in_array($ext, $conf['picture_ext'])) + { + if (isset($element_info['element_path']) ) + { + return $element_info['element_path']; + } + return get_element_path($element_info); + } + + $path = get_image_location($element_info); + if ( !url_is_remote($path) ) + { + $path = PHPWG_ROOT_PATH.$path; + } + return $path; +} + +/** + * Returns the URL of the image to be displayed in the picture page. If the + * element is not a picture, then the representative image or the default + * mime image. The URL can't be used in the php script, but can be sent to the + * browser. + * @param element_info array containing element information from db; + * at least 'id', 'path', 'representative_ext' should be present + */ +function get_image_url($element_info) +{ + global $conf; + $ext = get_extension($element_info['path']); + if (in_array($ext, $conf['picture_ext'])) + { + if (isset($element_info['element_url']) ) + { + return $element_info['element_url']; + } + return get_element_url($element_info); + } + + $url = get_image_location($element_info); + if ( !url_is_remote($url) ) + { + $url = embellish_url(get_root_url().$url); + } + return $url; +} + +/** + * Returns the relative path of the image (element/representative/mimetype) + * with regards to the root of PWG (not the current page). This function + * is not intended to be called directly from code. + * @param element_info array containing element information from db; + * at least 'id', 'path', 'representative_ext' should be present + */ +function get_image_location($element_info) +{ + if (isset($element_info['representative_ext']) + and $element_info['representative_ext'] != '') + { + $pi = pathinfo($element_info['path']); + $file_wo_ext = get_filename_wo_extension($pi['basename']); + $path = + $pi['dirname'].'/pwg_representative/' + .$file_wo_ext.'.'.$element_info['representative_ext']; + } + else + { + $ext = get_extension($element_info['path']); + $path = get_themeconf('mime_icon_dir'); + $path.= strtolower($ext).'.png'; + if ( !file_exists(PHPWG_ROOT_PATH.$path) + and !empty($element_info['tn_ext']) ) + { + $path = get_thumbnail_location($element_info); + } + } + + // plugins want another location ? + return trigger_event( 'get_image_location', $path, $element_info); +} + + +/* + * @param element_info array containing element information from db; + * at least 'id', 'path', 'has_high' should be present + */ +function get_high_path($element_info) +{ + $path = get_high_location($element_info); + if (!empty($path) and !url_is_remote($path) ) + { + $path = PHPWG_ROOT_PATH.$path; + } + return $path; +} + +/** + * @param element_info array containing element information from db; + * at least 'id', 'path', 'has_high' should be present + */ +function get_high_url($element_info) +{ + $url = get_high_location($element_info); + if (!empty($url) and !url_is_remote($url) ) + { + $url = embellish_url(get_root_url().$url); + } + // plugins want another url ? + return trigger_event('get_high_url', $url, $element_info); +} + +/** + * @param element_info array containing element information from db; + * at least 'id', 'path', 'has_high' should be present + */ +function get_high_location($element_info) +{ + $location = ''; + if ($element_info['has_high'] == 'true') + { + $pi = pathinfo($element_info['path']); + $location=$pi['dirname'].'/pwg_high/'.$pi['basename']; + } + return trigger_event( 'get_high_location', $location, $element_info); +} + + +/** + * @param what_part string one of 't' (thumbnail), 'e' (element), 'i' (image), + * 'h' (high resolution image) + * @param element_info array containing element information from db; + * at least 'id', 'path' should be present + */ +function get_download_url($what_part, $element_info) +{ + $url = get_root_url().'action.php'; + $url = add_url_params($url, + array( + 'id' => $element_info['id'], + 'part' => $what_part, + ) + ); + return trigger_event( 'get_download_url', $url, $element_info); +} + +/* + * get slideshow default params into array + * + * @param void + * + * @return slideshow default values into array + */ +function get_default_slideshow_params() +{ + global $conf; + + return array( + 'period' => $conf['slideshow_period'], + 'repeat' => $conf['slideshow_repeat'], + 'play' => true, + ); +} + +/* + * check and correct slideshow params from array + * + * @param array of params + * + * @return slideshow corrected values into array + */ +function correct_slideshow_params($params = array()) +{ + global $conf; + + if ($params['period'] < $conf['slideshow_period_min']) + { + $params['period'] = $conf['slideshow_period_min']; + } + else if ($params['period'] > $conf['slideshow_period_max']) + { + $params['period'] = $conf['slideshow_period_max']; + } + + return $params; +} + +/* + * Decode slideshow string params into array + * + * @param string params like "" + * + * @return slideshow values into array + */ +function decode_slideshow_params($encode_params = null) +{ + global $conf; + + $result = get_default_slideshow_params(); + + if (is_numeric($encode_params)) + { + $result['period'] = $encode_params; + } + else + { + $matches = array(); + if (preg_match_all('/([a-z]+)-(\d+)/', $encode_params, $matches)) + { + $matchcount = count($matches[1]); + for ($i = 0; $i < $matchcount; $i++) + { + $result[$matches[1][$i]] = $matches[2][$i]; + } + } + + if (preg_match_all('/([a-z]+)-(true|false)/', $encode_params, $matches)) + { + $matchcount = count($matches[1]); + for ($i = 0; $i < $matchcount; $i++) + { + $result[$matches[1][$i]] = get_boolean($matches[2][$i]); + } + } + } + + return correct_slideshow_params($result); +} + +/* + * Encode slideshow array params into array + * + * @param array params + * + * @return slideshow values into string + */ +function encode_slideshow_params($decode_params = array()) +{ + global $conf; + + $params = array_diff_assoc(correct_slideshow_params($decode_params), get_default_slideshow_params()); + $result = ''; + + foreach ($params as $name => $value) + { + // boolean_to_string return $value, if it's not a bool + $result .= '+'.$name.'-'.boolean_to_string($value); + } + + return $result; +} + +?> diff --git a/BSF/include/functions_plugins.inc.php b/BSF/include/functions_plugins.inc.php new file mode 100644 index 000000000..e2beb18ac --- /dev/null +++ b/BSF/include/functions_plugins.inc.php @@ -0,0 +1,284 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/* +Events and event handlers are the core of Piwigo plugin management. +Plugins are addons that are found in plugins subdirectory. If activated, PWG +will include the index.php of each plugin. +Events are triggered by PWG core code. Plugins (or even PWG itself) can +register their functions to handle these events. An event is identified by a +string. +*/ + +define('PHPWG_PLUGINS_PATH', PHPWG_ROOT_PATH.'plugins/'); + +define('EVENT_HANDLER_PRIORITY_NEUTRAL', 50); + +/* Register a event handler. + * @param string $event the name of the event to listen to + * @param mixed $func the function that will handle the event + * @param int $priority optional priority (greater priority will + * be executed at last) +*/ +function add_event_handler($event, $func, + $priority=EVENT_HANDLER_PRIORITY_NEUTRAL, $accepted_args=1) +{ + global $pwg_event_handlers; + + if ( isset($pwg_event_handlers[$event][$priority]) ) + { + foreach($pwg_event_handlers[$event][$priority] as $handler) + { + if ( $handler['function'] == $func ) + { + return false; + } + } + } + + $pwg_event_handlers[$event][$priority][] = + array( + 'function'=>$func, + 'accepted_args'=>$accepted_args); + ksort( $pwg_event_handlers[$event] ); + return true; +} + +/* Register a event handler. + * @param string $event the name of the event to listen to + * @param mixed $func the function that needs removal + * @param int $priority optional priority (greater priority will + * be executed at last) +*/ +function remove_event_handler($event, $func, + $priority=EVENT_HANDLER_PRIORITY_NEUTRAL) +{ + global $pwg_event_handlers; + + if (!isset( $pwg_event_handlers[$event][$priority] ) ) + { + return false; + } + for ($i=0; $i<count($pwg_event_handlers[$event][$priority]); $i++) + { + if ($pwg_event_handlers[$event][$priority][$i]['function']==$func) + { + unset($pwg_event_handlers[$event][$priority][$i]); + $pwg_event_handlers[$event][$priority] = + array_values($pwg_event_handlers[$event][$priority]); + + if ( empty($pwg_event_handlers[$event][$priority]) ) + { + unset( $pwg_event_handlers[$event][$priority] ); + if (empty( $pwg_event_handlers[$event] ) ) + { + unset( $pwg_event_handlers[$event] ); + } + } + return true; + } + } + return false; +} + +/* Triggers an event and calls all registered event handlers + * @param string $event name of the event + * @param mixed $data data to pass to handlers +*/ +function trigger_event($event, $data=null) +{ + global $pwg_event_handlers; + + // just for debugging + trigger_action('pre_trigger_event', + array('event'=>$event, 'data'=>$data) ); + + if ( !isset($pwg_event_handlers[$event]) ) + { + trigger_action('post_trigger_event', + array('event'=>$event, 'data'=>$data) ); + return $data; + } + $args = array_slice(func_get_args(), 2); + + foreach ($pwg_event_handlers[$event] as $priority => $handlers) + { + if ( !is_null($handlers) ) + { + foreach($handlers as $handler) + { + $all_args = array_merge( array($data), $args); + $function_name = $handler['function']; + $accepted_args = $handler['accepted_args']; + + if ( $accepted_args == 1 ) + $the_args = array($data); + elseif ( $accepted_args > 1 ) + $the_args = array_slice($all_args, 0, $accepted_args); + elseif ( $accepted_args == 0 ) + $the_args = NULL; + else + $the_args = $all_args; + + $data = call_user_func_array($function_name, $the_args); + } + } + } + trigger_action('post_trigger_event', + array('event'=>$event, 'data'=>$data) ); + return $data; +} + +function trigger_action($event, $data=null) +{ + global $pwg_event_handlers; + if ($event!='pre_trigger_event' + and $event!='post_trigger_event' + and $event!='trigger_action') + {// special case for debugging - avoid recursive calls + trigger_action('trigger_action', + array('event'=>$event, 'data'=>$data) ); + } + + if ( !isset($pwg_event_handlers[$event]) ) + { + return; + } + $args = array_slice(func_get_args(), 2); + + foreach ($pwg_event_handlers[$event] as $priority => $handlers) + { + if ( !is_null($handlers) ) + { + foreach($handlers as $handler) + { + $all_args = array_merge( array($data), $args); + $function_name = $handler['function']; + $accepted_args = $handler['accepted_args']; + + if ( $accepted_args == 1 ) + $the_args = array($data); + elseif ( $accepted_args > 1 ) + $the_args = array_slice($all_args, 0, $accepted_args); + elseif ( $accepted_args == 0 ) + $the_args = NULL; + else + $the_args = $all_args; + + call_user_func_array($function_name, $the_args); + } + } + } +} + +/** Saves some data with the associated plugim id. It can be retrieved later ( + * during this script lifetime) using get_plugin_data + * @param string plugin_id + * @param mixed data + * returns true on success, false otherwise + */ +function set_plugin_data($plugin_id, &$data) +{ + global $pwg_loaded_plugins; + if ( isset($pwg_loaded_plugins[$plugin_id]) ) + { + $pwg_loaded_plugins[$plugin_id]['plugin_data'] = &$data; + return true; + } + return false; +} + +/** Retrieves plugin data saved previously with set_plugin_data + * @param string plugin_id + */ +function &get_plugin_data($plugin_id) +{ + global $pwg_loaded_plugins; + if ( isset($pwg_loaded_plugins[$plugin_id]) ) + { + return $pwg_loaded_plugins[$plugin_id]['plugin_data']; + } + return null; +} + +/* Returns an array of plugins defined in the database + * @param string $state optional filter on this state + * @param string $id optional returns only data about given plugin +*/ +function get_db_plugins($state='', $id='') +{ + $query = ' +SELECT * FROM '.PLUGINS_TABLE; + if (!empty($state) or !empty($id) ) + { + $query .= ' +WHERE 1=1'; + if (!empty($state)) + { + $query .= ' + AND state="'.$state.'"'; + } + if (!empty($id)) + { + $query .= ' + AND id="'.$id.'"'; + } + } + + $result = pwg_query($query); + $plugins = array(); + while ($row = mysql_fetch_array($result)) + { + array_push($plugins, $row); + } + return $plugins; +} + + +function load_plugin($plugin) +{ + $file_name = PHPWG_PLUGINS_PATH.$plugin['id'].'/main.inc.php'; + if ( file_exists($file_name) ) + { + global $pwg_loaded_plugins; + $pwg_loaded_plugins[ $plugin['id'] ] = $plugin; + include_once( $file_name ); + } +} + +/*loads all the plugins on startup*/ +function load_plugins() +{ + global $conf, $pwg_loaded_plugins; + $pwg_loaded_plugins = array(); + if ($conf['enable_plugins']) + { + $plugins = get_db_plugins('active'); + foreach( $plugins as $plugin) + {// include main from a function to avoid using same function context + load_plugin($plugin); + } + trigger_action('plugins_loaded'); + } +} +?>
\ No newline at end of file diff --git a/BSF/include/functions_rate.inc.php b/BSF/include/functions_rate.inc.php new file mode 100644 index 000000000..ad3de1b2f --- /dev/null +++ b/BSF/include/functions_rate.inc.php @@ -0,0 +1,134 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * rate a picture by a user + * + * @param int image identifier + * @param int rate + * @return void + */ +function rate_picture($image_id, $rate) +{ + global $conf, $user; + + if (!isset($rate) + or !$conf['rate'] + or !in_array($rate, $conf['rate_items'])) + { + return; + } + + $user_anonymous = is_autorize_status(ACCESS_CLASSIC) ? false : true; + + if ($user_anonymous and !$conf['rate_anonymous']) + { + return; + } + + $ip_components = explode('.', $_SERVER["REMOTE_ADDR"]); + if (count($ip_components) > 3) + { + array_pop($ip_components); + } + $anonymous_id = implode ('.', $ip_components); + + if ($user_anonymous) + { + $save_anonymous_id = pwg_get_cookie_var('anonymous_rater', $anonymous_id); + + if ($anonymous_id != $save_anonymous_id) + { // client has changed his IP adress or he's trying to fool us + $query = ' +SELECT element_id + FROM '.RATE_TABLE.' + WHERE user_id = '.$user['id'].' + AND anonymous_id = \''.$anonymous_id.'\' +;'; + $already_there = array_from_query($query, 'element_id'); + + if (count($already_there) > 0) + { + $query = ' +DELETE + FROM '.RATE_TABLE.' + WHERE user_id = '.$user['id'].' + AND anonymous_id = \''.$save_anonymous_id.'\' + AND element_id IN ('.implode(',', $already_there).') +;'; + pwg_query($query); + } + + $query = ' +UPDATE '.RATE_TABLE.' + SET anonymous_id = \'' .$anonymous_id.'\' + WHERE user_id = '.$user['id'].' + AND anonymous_id = \'' . $save_anonymous_id.'\' +;'; + pwg_query($query); + } // end client changed ip + + pwg_set_cookie_var('anonymous_rater', $anonymous_id); + } // end anonymous user + + $query = ' +DELETE + FROM '.RATE_TABLE.' + WHERE element_id = '.$image_id.' + AND user_id = '.$user['id'].' +'; + if (isset($user_anonymous)) + { + $query.= ' AND anonymous_id = \''.$anonymous_id.'\''; + } + pwg_query($query); + $query = ' +INSERT + INTO '.RATE_TABLE.' + (user_id,anonymous_id,element_id,rate,date) + VALUES + (' + .$user['id'].',' + .'\''.$anonymous_id.'\',' + .$image_id.',' + .$rate + .',NOW()) +;'; + pwg_query($query); + + // update of images.average_rate field + $query = ' +SELECT ROUND(AVG(rate),2) AS average_rate + FROM '.RATE_TABLE.' + WHERE element_id = '.$image_id.' +;'; + $row = mysql_fetch_array(pwg_query($query)); + $query = ' +UPDATE '.IMAGES_TABLE.' + SET average_rate = '.$row['average_rate'].' + WHERE id = '.$image_id.' +;'; + pwg_query($query); +} + +?>
\ No newline at end of file diff --git a/BSF/include/functions_search.inc.php b/BSF/include/functions_search.inc.php new file mode 100644 index 000000000..7069bd5c9 --- /dev/null +++ b/BSF/include/functions_search.inc.php @@ -0,0 +1,560 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + + +/** + * returns search rules stored into a serialized array in "search" + * table. Each search rules set is numericaly identified. + * + * @param int search_id + * @return array + */ +function get_search_array($search_id) +{ + if (!is_numeric($search_id)) + { + die('Search id must be an integer'); + } + + $query = ' +SELECT rules + FROM '.SEARCH_TABLE.' + WHERE id = '.$search_id.' +;'; + list($serialized_rules) = mysql_fetch_row(pwg_query($query)); + + return unserialize($serialized_rules); +} + +/** + * returns the SQL clause from a search identifier + * + * Search rules are stored in search table as a serialized array. This array + * need to be transformed into an SQL clause to be used in queries. + * + * @param array search + * @return string + */ +function get_sql_search_clause($search) +{ + // SQL where clauses are stored in $clauses array during query + // construction + $clauses = array(); + + foreach (array('file','name','comment','author') as $textfield) + { + if (isset($search['fields'][$textfield])) + { + $local_clauses = array(); + foreach ($search['fields'][$textfield]['words'] as $word) + { + array_push($local_clauses, $textfield." LIKE '%".$word."%'"); + } + + // adds brackets around where clauses + $local_clauses = prepend_append_array_items($local_clauses, '(', ')'); + + array_push( + $clauses, + implode( + ' '.$search['fields'][$textfield]['mode'].' ', + $local_clauses + ) + ); + } + } + + if (isset($search['fields']['allwords'])) + { + $fields = array('file', 'name', 'comment', 'author'); + // in the OR mode, request bust be : + // ((field1 LIKE '%word1%' OR field2 LIKE '%word1%') + // OR (field1 LIKE '%word2%' OR field2 LIKE '%word2%')) + // + // in the AND mode : + // ((field1 LIKE '%word1%' OR field2 LIKE '%word1%') + // AND (field1 LIKE '%word2%' OR field2 LIKE '%word2%')) + $word_clauses = array(); + foreach ($search['fields']['allwords']['words'] as $word) + { + $field_clauses = array(); + foreach ($fields as $field) + { + array_push($field_clauses, $field." LIKE '%".$word."%'"); + } + // adds brackets around where clauses + array_push( + $word_clauses, + implode( + "\n OR ", + $field_clauses + ) + ); + } + + array_walk( + $word_clauses, + create_function('&$s','$s="(".$s.")";') + ); + + array_push( + $clauses, + "\n ". + implode( + "\n ". + $search['fields']['allwords']['mode']. + "\n ", + $word_clauses + ) + ); + } + + foreach (array('date_available', 'date_creation') as $datefield) + { + if (isset($search['fields'][$datefield])) + { + array_push( + $clauses, + $datefield." = '".$search['fields'][$datefield]['date']."'" + ); + } + + foreach (array('after','before') as $suffix) + { + $key = $datefield.'-'.$suffix; + + if (isset($search['fields'][$key])) + { + array_push( + $clauses, + + $datefield. + ($suffix == 'after' ? ' >' : ' <'). + ($search['fields'][$key]['inc'] ? '=' : ''). + " '".$search['fields'][$key]['date']."'" + + ); + } + } + } + + if (isset($search['fields']['cat'])) + { + if ($search['fields']['cat']['sub_inc']) + { + // searching all the categories id of sub-categories + $cat_ids = get_subcat_ids($search['fields']['cat']['words']); + } + else + { + $cat_ids = $search['fields']['cat']['words']; + } + + $local_clause = 'category_id IN ('.implode(',', $cat_ids).')'; + array_push($clauses, $local_clause); + } + + // adds brackets around where clauses + $clauses = prepend_append_array_items($clauses, '(', ')'); + + $where_separator = + implode( + "\n ".$search['mode'].' ', + $clauses + ); + + $search_clause = $where_separator; + + return $search_clause; +} + +/** + * returns the list of items corresponding to the advanced search array + * + * @param array search + * @return array + */ +function get_regular_search_results($search) +{ + $items = array(); + + $search_clause = get_sql_search_clause($search); + + if (!empty($search_clause)) + { + $query = ' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE '.$search_clause.' +;'; + $items = array_from_query($query, 'id'); + } + + if (isset($search['fields']['tags'])) + { + $tag_items = get_image_ids_for_tags( + $search['fields']['tags']['words'], + $search['fields']['tags']['mode'] + ); + + switch ($search['mode']) + { + case 'AND': + { + if (empty($search_clause)) + { + $items = $tag_items; + } + else + { + $items = array_intersect($items, $tag_items); + } + break; + } + case 'OR': + { + $items = array_unique( + array_merge( + $items, + $tag_items + ) + ); + break; + } + } + } + + return $items; +} + +/** + * returns the LIKE sql clause corresponding to the quick search query $q + * and the field $field. example q='john bill', field='file' will return + * file LIKE '%john%' OR file LIKE '%bill%'. Special characters for MySql full + * text search (+,<,>,~) are omitted. The query can contain a phrase: + * 'Pierre "New York"' will return LIKE '%Pierre%' OR LIKE '%New York%'. + * @param string q + * @param string field + * @return string + */ +function get_qsearch_like_clause($q, $field) +{ + $q = stripslashes($q); + $tokens = array(); + $token_modifiers = array(); + $crt_token = ""; + $crt_token_modifier = ""; + $state = 0; + + for ($i=0; $i<strlen($q); $i++) + { + $ch = $q[$i]; + switch ($state) + { + case 0: + if ($ch=='"') + { + if (strlen($crt_token)) + { + $tokens[] = $crt_token; + $token_modifiers[] = $crt_token_modifier; + $crt_token = ""; + $crt_token_modifier = ""; + } + $state=1; + } + elseif ( $ch=='*' ) + { // wild card + $crt_token .= '%'; + } + elseif ( strcspn($ch, '+-><~')==0 ) + { //special full text modifier + if (strlen($crt_token)) + { + $tokens[] = $crt_token; + $token_modifiers[] = $crt_token_modifier; + $crt_token = ""; + $crt_token_modifier = ""; + } + $crt_token_modifier .= $ch; + } + elseif (preg_match('/[\s,.;!\?]+/', $ch)) + { // white space + if (strlen($crt_token)) + { + $tokens[] = $crt_token; + $token_modifiers[] = $crt_token_modifier; + $crt_token = ""; + $crt_token_modifier = ""; + } + } + else + { + $crt_token .= $ch; + } + break; + case 1: // qualified with quotes + switch ($ch) + { + case '"': + $tokens[] = $crt_token; + $token_modifiers[] = $crt_token_modifier; + $crt_token = ""; + $crt_token_modifier = ""; + $state=0; + break; + default: + $crt_token .= $ch; + } + break; + } + } + if (strlen($crt_token)) + { + $tokens[] = $crt_token; + $token_modifiers[] = $crt_token_modifier; + } + + $clauses = array(); + for ($i=0; $i<count($tokens); $i++) + { + $tokens[$i] = trim($tokens[$i], '%'); + if (strstr($token_modifiers[$i], '-')!==false) + continue; + if ( strlen($tokens[$i])==0) + continue; + $clauses[] = $field.' LIKE "%'.addslashes($tokens[$i]).'%"'; + } + + return count($clauses) ? '('.implode(' OR ', $clauses).')' : null; +} + + +/** + * returns the search results corresponding to a quick/query search. + * A quick/query search returns many items (search is not strict), but results + * are sorted by relevance unless $page['super_order_by'] is set. Returns: + * array ( + * 'items' => array(85,68,79...) + * 'as_is' => 1 (indicates the caller that items are ordered and permissions checked + * 'qs' => array( + * 'matching_tags' => array of matching tags + * 'matching_cats' => array of matching categories + * 'matching_cats_no_images' =>array(99) - matching categories without images + * )) + * + * @param string q + * @param string images_where optional aditional restriction on images table + * @return array + */ +function get_quick_search_results($q, $images_where='') +{ + global $page; + $search_results = + array( + 'items' => array(), + 'as_is' => 1, + 'qs' => array('q'=>stripslashes($q)), + ); + $q = trim($q); + if (empty($q)) + { + return $search_results; + } + $q_like_field = '@@__db_field__@@'; //something never in a search + $q_like_clause = get_qsearch_like_clause($q, $q_like_field ); + + + // Step 1 - first we find matches in #images table =========================== + $where_clauses='MATCH(i.name, i.comment) AGAINST( "'.$q.'" IN BOOLEAN MODE)'; + if (!empty($q_like_clause)) + { + $where_clauses .= ' + OR '. str_replace($q_like_field, 'file', $q_like_clause); + $where_clauses = '('.$where_clauses.')'; + } + $where_clauses = array($where_clauses); + if (!empty($images_where)) + { + $where_clauses[]='('.$images_where.')'; + } + $where_clauses[] .= get_sql_condition_FandF + ( + array( 'visible_images' => 'i.id' ), null, true + ); + $query = ' +SELECT i.id, + MATCH(i.name, i.comment) AGAINST( "'.$q.'" IN BOOLEAN MODE) AS weight + FROM '.IMAGES_TABLE.' i + WHERE '.implode("\n AND ", $where_clauses); + + $by_weights=array(); + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { // weight is important when sorting images by relevance + if ($row['weight']) + { + $by_weights[(int)$row['id']] = 2*$row['weight']; + } + else + {//full text does not match but file name match + $by_weights[(int)$row['id']] = 2; + } + } + + + // Step 2 - search tags corresponding to the query $q ======================== + if (!empty($q_like_clause)) + { // search name and url name (without accents) + $query = ' +SELECT id, name, url_name + FROM '.TAGS_TABLE.' + WHERE ('.str_replace($q_like_field, 'CONVERT(name, CHAR)', $q_like_clause).' + OR '.str_replace($q_like_field, 'url_name', $q_like_clause).')'; + $tags = hash_from_query($query, 'id'); + if ( !empty($tags) ) + { // we got some tags; get the images + $search_results['qs']['matching_tags']=$tags; + $query = ' +SELECT image_id, COUNT(tag_id) AS weight + FROM '.IMAGE_TAG_TABLE.' + WHERE tag_id IN ('.implode(',',array_keys($tags)).') + GROUP BY image_id'; + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { // weight is important when sorting images by relevance + $image_id=(int)$row['image_id']; + @$by_weights[$image_id] += $row['weight']; + } + } + } + + + // Step 3 - search categories corresponding to the query $q ================== + global $user; + $query = ' +SELECT id, name, permalink, nb_images + FROM '.CATEGORIES_TABLE.' + INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' ON id=cat_id + WHERE user_id='.$user['id'].' + AND MATCH(name, comment) AGAINST( "'.$q.'" IN BOOLEAN MODE)'. + get_sql_condition_FandF ( + array( 'visible_categories' => 'cat_id' ), "\n AND" + ); + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { // weight is important when sorting images by relevance + if ($row['nb_images']==0) + { + $search_results['qs']['matching_cats_no_images'][] = $row; + } + else + { + $search_results['qs']['matching_cats'][$row['id']] = $row; + } + } + + if ( empty($by_weights) and empty($search_results['qs']['matching_cats']) ) + { + return $search_results; + } + + // Step 4 - now we have $by_weights ( array image id => weight ) that need + // permission checks and/or matching categories to get images from + $where_clauses = array(); + if ( !empty($by_weights) ) + { + $where_clauses[]='i.id IN (' + . implode(',', array_keys($by_weights)) . ')'; + } + if ( !empty($search_results['qs']['matching_cats']) ) + { + $where_clauses[]='category_id IN ('. + implode(',',array_keys($search_results['qs']['matching_cats'])).')'; + } + $where_clauses = array( '('.implode("\n OR ",$where_clauses).')' ); + if (!empty($images_where)) + { + $where_clauses[]='('.$images_where.')'; + } + $where_clauses[] = get_sql_condition_FandF( + array + ( + 'forbidden_categories' => 'category_id', + 'visible_categories' => 'category_id', + 'visible_images' => 'i.id' + ), + null,true + ); + + global $conf; + $query = ' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' i + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE '.implode("\n AND ", $where_clauses)."\n". + $conf['order_by']; + + $allowed_images = array_from_query( $query, 'id'); + + if ( isset($page['super_order_by']) or empty($by_weights) ) + { + $search_results['items'] = $allowed_images; + return $search_results; + } + + $allowed_images = array_flip( $allowed_images ); + $divisor = 5.0 * count($allowed_images); + foreach ($allowed_images as $id=>$rank ) + { + $weight = isset($by_weights[$id]) ? $by_weights[$id] : 1; + $weight -= $rank/$divisor; + $allowed_images[$id] = $weight; + } + arsort($allowed_images, SORT_NUMERIC); + $search_results['items'] = array_keys($allowed_images); + return $search_results; +} + +/** + * returns an array of 'items' corresponding to the search id + * + * @param int search id + * @param string images_where optional aditional restriction on images table + * @return array + */ +function get_search_results($search_id, $images_where='') +{ + $search = get_search_array($search_id); + if ( !isset($search['q']) ) + { + $result['items'] = get_regular_search_results($search); + return $result; + } + else + { + return get_quick_search_results($search['q'], $images_where); + } +} +?>
\ No newline at end of file diff --git a/BSF/include/functions_session.inc.php b/BSF/include/functions_session.inc.php new file mode 100644 index 000000000..f17f2377a --- /dev/null +++ b/BSF/include/functions_session.inc.php @@ -0,0 +1,225 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// The function generate_key creates a string with pseudo random characters. +// the size of the string depends on the $conf['session_id_size']. +// Characters used are a-z A-Z and numerical values. Examples : +// "Er4Tgh6", "Rrp08P", "54gj" +// input : none (using global variable) +// output : $key +function generate_key($size) +{ + global $conf; + + $md5 = md5(substr(microtime(), 2, 6)); + $init = ''; + for ( $i = 0; $i < strlen( $md5 ); $i++ ) + { + if ( is_numeric( $md5[$i] ) ) $init.= $md5[$i]; + } + $init = substr( $init, 0, 8 ); + mt_srand( $init ); + $key = ''; + for ( $i = 0; $i < $size; $i++ ) + { + $c = mt_rand( 0, 2 ); + if ( $c == 0 ) $key .= chr( mt_rand( 65, 90 ) ); + else if ( $c == 1 ) $key .= chr( mt_rand( 97, 122 ) ); + else $key .= mt_rand( 0, 9 ); + } + return $key; +} + +if (isset($conf['session_save_handler']) + and ($conf['session_save_handler'] == 'db') + and defined('PHPWG_INSTALLED')) +{ + session_set_save_handler('pwg_session_open', + 'pwg_session_close', + 'pwg_session_read', + 'pwg_session_write', + 'pwg_session_destroy', + 'pwg_session_gc' + ); + if ( function_exists('ini_set') ) + { + ini_set('session.use_cookies', $conf['session_use_cookies']); + ini_set('session.use_only_cookies', $conf['session_use_only_cookies']); + ini_set('session.use_trans_sid', intval($conf['session_use_trans_sid'])); + } + session_name($conf['session_name']); + session_set_cookie_params(0, cookie_path()); +} + +/** + * returns true; used when the session_start() function is called + * + * @params not use but useful for php engine + */ +function pwg_session_open($path, $name) +{ + return true; +} + +/** + * returns true; used when the session is closed (unset($_SESSION)) + * + */ +function pwg_session_close() +{ + return true; +} + +/** + * this function returns + * a string corresponding to the value of the variable save in the session + * or an empty string when the variable doesn't exist + * + * @param string session id + */ +function pwg_session_read($session_id) +{ + $query = ' +SELECT data + FROM '.SESSIONS_TABLE.' + WHERE id = \''.$session_id.'\' +;'; + $result = pwg_query($query); + if ($result) + { + $row = mysql_fetch_assoc($result); + return $row['data']; + } + else + { + return ''; + } +} + +/** + * returns true; writes set a variable in the active session + * + * @param string session id + * @data string value of date to be saved + */ +function pwg_session_write($session_id, $data) +{ + $query = ' +UPDATE '.SESSIONS_TABLE.' + SET expiration = now(), + data = \''.$data.'\' + WHERE id = \''.$session_id.'\' +;'; + pwg_query($query); + if ( mysql_affected_rows()>0 ) + { + return true; + } + $query = ' +INSERT INTO '.SESSIONS_TABLE.' + (id,data,expiration) + VALUES(\''.$session_id.'\',\''.$data.'\',now()) +;'; + mysql_query($query); + return true; +} + +/** + * returns true; delete the active session + * + * @param string session id + */ +function pwg_session_destroy($session_id) +{ + $query = ' +DELETE + FROM '.SESSIONS_TABLE.' + WHERE id = \''.$session_id.'\' +;'; + pwg_query($query); + return true; +} + +/** + * returns true; delete expired sessions + * called each time a session is closed. + */ +function pwg_session_gc() +{ + global $conf; + + $query = ' +DELETE + FROM '.SESSIONS_TABLE.' + WHERE UNIX_TIMESTAMP(NOW()) - UNIX_TIMESTAMP(expiration) > ' + .$conf['session_length'].' +;'; + pwg_query($query); + return true; +} + + +/** + * persistently stores a variable for the current session + * currently we use standard php sessions but it might change + * @return boolean true on success + * @see pwg_get_session_var, pwg_unset_session_var + */ +function pwg_set_session_var($var, $value) +{ + if ( !isset($_SESSION) ) + return false; + $_SESSION['pwg_'.$var] = $value; + return true; +} + +/** + * retrieves the value of a persistent variable for the current session + * currently we use standard php sessions but it might change + * @return mixed + * @see pwg_set_session_var, pwg_unset_session_var + */ +function pwg_get_session_var($var, $default = null) +{ + if (isset( $_SESSION['pwg_'.$var] ) ) + { + return $_SESSION['pwg_'.$var]; + } + return $default; +} + +/** + * deletes a persistent variable for the current session + * currently we use standard php sessions but it might change + * @return boolean true on success + * @see pwg_set_session_var, pwg_get_session_var + */ +function pwg_unset_session_var($var) +{ + if ( !isset($_SESSION) ) + return false; + unset( $_SESSION['pwg_'.$var] ); + return true; +} + +?> diff --git a/BSF/include/functions_tag.inc.php b/BSF/include/functions_tag.inc.php new file mode 100644 index 000000000..7bd5d8408 --- /dev/null +++ b/BSF/include/functions_tag.inc.php @@ -0,0 +1,323 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + + +/** + * Tags available. Each return tag is represented as an array with its id, + * its name, its weight (count), its url name. Tags are not sorted. + * + * The returned list can be a subset of all existing tags due to + * permissions, only if a list of forbidden categories is provided + * + * @param array forbidden categories + * @return array + */ +function get_available_tags() +{ + // we can find top fatter tags among reachable images + $query = ' +SELECT tag_id, COUNT(DISTINCT(it.image_id)) counter + FROM '.IMAGE_CATEGORY_TABLE.' ic + INNER JOIN '.IMAGE_TAG_TABLE.' it ON ic.image_id=it.image_id'.get_sql_condition_FandF + ( + array + ( + 'forbidden_categories' => 'category_id', + 'visible_categories' => 'category_id', + 'visible_images' => 'ic.image_id' + ), + ' + WHERE' + ).' + GROUP BY tag_id + ORDER BY NULL'; + $tag_counters = simple_hash_from_query($query, 'tag_id', 'counter'); + + if ( empty($tag_counters) ) + { + return array(); + } + + $query = ' +SELECT id, name, url_name + FROM '.TAGS_TABLE; + $result = pwg_query($query); + $tags = array(); + while ($row = mysql_fetch_assoc($result)) + { + $counter = @$tag_counters[ $row['id'] ]; + if ( $counter ) + { + $row['counter'] = $counter; + array_push($tags, $row); + } + } + return $tags; +} + +/** + * All tags, even tags associated to no image. + * + * @return array + */ +function get_all_tags() +{ + $query = ' +SELECT id, + name, + url_name + FROM '.TAGS_TABLE.' +;'; + $result = pwg_query($query); + $tags = array(); + while ($row = mysql_fetch_assoc($result)) + { + array_push($tags, $row); + } + + usort($tags, 'name_compare'); + + return $tags; +} + +/** + * Giving a set of tags with a counter for each one, calculate the display + * level of each tag. + * + * The level of each tag depends on the average count of tags. This + * calcylation method avoid having very different levels for tags having + * nearly the same count when set are small. + * + * @param array tags + * @return array + */ +function add_level_to_tags($tags) +{ + global $conf; + + if (count($tags) == 0) + { + return $tags; + } + + $total_count = 0; + + foreach ($tags as $tag) + { + $total_count+= $tag['counter']; + } + + // average count of available tags will determine the level of each tag + $tag_average_count = $total_count / count($tags); + + // tag levels threshold calculation: a tag with an average rate must have + // the middle level. + for ($i = 1; $i < $conf['tags_levels']; $i++) + { + $threshold_of_level[$i] = + 2 * $i * $tag_average_count / $conf['tags_levels']; + } + + // display sorted tags + foreach (array_keys($tags) as $k) + { + $tags[$k]['level'] = 1; + + // based on threshold, determine current tag level + for ($i = $conf['tags_levels'] - 1; $i >= 1; $i--) + { + if ($tags[$k]['counter'] > $threshold_of_level[$i]) + { + $tags[$k]['level'] = $i + 1; + break; + } + } + } + + return $tags; +} + +/** + * return the list of image ids corresponding to given tags. AND & OR mode + * supported. + * + * @param array tag ids + * @param string mode + * @return array + */ +function get_image_ids_for_tags($tag_ids, $mode = 'AND') +{ + switch ($mode) + { + case 'AND': + { + // strategy is to list images associated to each tag + $tag_images = array(); + + foreach ($tag_ids as $tag_id) + { + $query = ' +SELECT image_id + FROM '.IMAGE_TAG_TABLE.' + WHERE tag_id = '.$tag_id.' +;'; + $tag_images[$tag_id] = array_from_query($query, 'image_id'); + } + + // then we calculate the intersection, the images that are associated to + // every tags + $items = array_shift($tag_images); + foreach ($tag_images as $images) + { + $items = array_intersect($items, $images); + } + + return array_unique($items); + break; + } + case 'OR': + { + $query = ' +SELECT DISTINCT image_id + FROM '.IMAGE_TAG_TABLE.' + WHERE tag_id IN ('.implode(',', $tag_ids).') +;'; + return array_from_query($query, 'image_id'); + break; + } + default: + { + die('get_image_ids_for_tags: unknown mode, only AND & OR are supported'); + } + } +} + +/** + * return a list of tags corresponding to given items. + * + * @param array items + * @param array max_tags + * @param array excluded_tag_ids + * @return array + */ +function get_common_tags($items, $max_tags, $excluded_tag_ids=null) +{ + if (empty($items)) + { + return array(); + } + $query = ' +SELECT id, name, url_name, count(*) counter + FROM '.IMAGE_TAG_TABLE.' + INNER JOIN '.TAGS_TABLE.' ON tag_id = id + WHERE image_id IN ('.implode(',', $items).')'; + if (!empty($excluded_tag_ids)) + { + $query.=' + AND tag_id NOT IN ('.implode(',', $excluded_tag_ids).')'; + } + $query .=' + GROUP BY tag_id'; + if ($max_tags>0) + { + $query .= ' + ORDER BY counter DESC + LIMIT 0,'.$max_tags; + } + else + { + $query .= ' + ORDER BY NULL'; + } + + $result = pwg_query($query); + $tags = array(); + while($row = mysql_fetch_assoc($result)) + { + array_push($tags, $row); + } + usort($tags, 'name_compare'); + return $tags; +} + +/** + * return a list of tags corresponding to any of ids, url_names, names + * + * @param array ids + * @param array url_names + * @param array names + * @return array + */ +function find_tags($ids, $url_names=array(), $names=array() ) +{ + $where_clauses = array(); + if ( !empty($ids) ) + { + $where_clauses[] = 'id IN ('.implode(',', $ids).')'; + } + if ( !empty($url_names) ) + { + $where_clauses[] = + 'url_name IN ('. + implode( + ',', + array_map( + create_function('$s', 'return "\'".$s."\'";'), + $url_names + ) + ) + .')'; + } + if ( !empty($names) ) + { + $where_clauses[] = + 'name IN ('. + implode( + ',', + array_map( + create_function('$s', 'return "\'".$s."\'";'), + $names + ) + ) + .')'; + } + if (empty($where_clauses)) + { + return array(); + } + + $query = ' +SELECT id, url_name, name + FROM '.TAGS_TABLE.' + WHERE '. implode( ' + OR ', $where_clauses); + + $result = pwg_query($query); + $tags = array(); + while ($row = mysql_fetch_assoc($result)) + { + array_push($tags, $row); + } + return $tags; +} +?>
\ No newline at end of file diff --git a/BSF/include/functions_url.inc.php b/BSF/include/functions_url.inc.php new file mode 100644 index 000000000..fa7114dea --- /dev/null +++ b/BSF/include/functions_url.inc.php @@ -0,0 +1,740 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + + +/** + * returns a prefix for each url link on displayed page + * and return an empty string for current path + * @return string + */ +function get_root_url() +{ + global $page; + if ( isset($page['root_path']) ) + { + $root_url = $page['root_path']; + } + else + {// TODO - add HERE the possibility to call PWG functions from external scripts + $root_url = PHPWG_ROOT_PATH; + } + if ( dirname($root_url)!='.' ) + { + return $root_url; + } + else + { + return (string)substr($root_url, 2); + } +} + +/** + * returns the absolute url to the root of PWG + * @param boolean with_scheme if false - does not add http://toto.com + */ +function get_absolute_root_url($with_scheme=true) +{ + // TODO - add HERE the possibility to call PWG functions from external scripts + $url = ''; + if ($with_scheme) + { + if (empty($_SERVER['HTTPS'])) + { + $url .= 'http://'; + } + else + { + $url .= 'https://'; + } + $url .= $_SERVER['HTTP_HOST']; + if ($_SERVER['SERVER_PORT'] != 80) + { + $url_port = ':'.$_SERVER['SERVER_PORT']; + if (strrchr($url, ':') != $url_port) + { + $url .= $url_port; + } + } + } + $url .= cookie_path(); + return $url; +} + +/** + * adds one or more _GET style parameters to an url + * example: add_url_params('/x', array('a'=>'b')) returns /x?a=b + * add_url_params('/x?cat_id=10', array('a'=>'b')) returns /x?cat_id=10&a=b + * @param string url + * @param array params + * @return string + */ +function add_url_params($url, $params) +{ + if ( !empty($params) ) + { + assert( is_array($params) ); + $is_first = true; + foreach($params as $param=>$val) + { + if ($is_first) + { + $is_first = false; + $url .= ( strstr($url, '?')===false ) ? '?' :'&'; + } + else + { + $url .= '&'; + } + $url .= $param; + if (isset($val)) + { + $url .= '='.$val; + } + } + } + return $url; +} + +/** + * build an index URL for a specific section + * + * @param array + * @return string + */ +function make_index_url($params = array()) +{ + global $conf; + $url = get_root_url().'index'; + if ($conf['php_extension_in_urls']) + { + $url .= '.php'; + } + if ($conf['question_mark_in_urls']) + { + $url .= '?'; + } + $url.= make_section_in_url($params); + $url = add_well_known_params_in_url($url, $params); + return $url; +} + +/** + * build an index URL with current page parameters, but with redefinitions + * and removes. + * + * duplicate_index_url( array( + * 'category' => array('id'=>12, 'name'=>'toto'), + * array('start') + * ) will create an index URL on the current section (categories), but on + * a redefined category and without the start URL parameter. + * + * @param array redefined keys + * @param array removed keys + * @return string + */ +function duplicate_index_url($redefined = array(), $removed = array()) +{ + return make_index_url( + params_for_duplication($redefined, $removed) + ); +} + +/** + * returns $page global array with key redefined and key removed + * + * @param array redefined keys + * @param array removed keys + * @return array + */ +function params_for_duplication($redefined, $removed) +{ + global $page; + + if (count($removed) > 0) + { + $params = array(); + + foreach ($page as $page_item_key => $page_item_value) + { + if (!in_array($page_item_key, $removed)) + { + $params[$page_item_key] = $page_item_value; + } + } + } + else + { + $params = $page; + } + + foreach ($redefined as $redefined_param => $redefined_value) + { + $params[$redefined_param] = $redefined_value; + } + + return $params; +} + +/** + * create a picture URL with current page parameters, but with redefinitions + * and removes. See duplicate_index_url. + * + * @param array redefined keys + * @param array removed keys + * @return string + */ +function duplicate_picture_url($redefined = array(), $removed = array()) +{ + return make_picture_url( + params_for_duplication($redefined, $removed) + ); +} + +/** + * create a picture URL on a specific section for a specific picture + * + * @param array + * @return string + */ +function make_picture_url($params) +{ + global $conf; + if (!isset($params['image_id'])) + { + die('make_picture_url: image_id is a required parameter'); + } + + $url = get_root_url().'picture'; + if ($conf['php_extension_in_urls']) + { + $url .= '.php'; + } + if ($conf['question_mark_in_urls']) + { + $url .= '?'; + } + $url.= '/'; + switch ( $conf['picture_url_style'] ) + { + case 'id-file': + $url .= $params['image_id']; + if ( isset($params['image_file']) ) + { + $url .= '-'.get_filename_wo_extension($params['image_file']); + } + break; + case 'file': + if ( isset($params['image_file']) ) + { + $fname_wo_ext = get_filename_wo_extension($params['image_file']); + if (! preg_match('/^\d+(-|$)/', $fname_wo_ext) ) + { + $url .= $fname_wo_ext; + break; + } + } + default: + $url .= $params['image_id']; + } + if ( !isset($params['category'] ) ) + {// make urls shorter ... + unset( $params['flat'] ); + } + $url .= make_section_in_url($params); + $url = add_well_known_params_in_url($url, $params); + return $url; +} + +/** + *adds to the url the chronology and start parameters +*/ +function add_well_known_params_in_url($url, $params) +{ + if ( isset($params['chronology_field']) ) + { + $url .= '/'. $params['chronology_field']; + $url .= '-'. $params['chronology_style']; + if ( isset($params['chronology_view']) ) + { + $url .= '-'. $params['chronology_view']; + } + if ( !empty($params['chronology_date']) ) + { + $url .= '-'. implode('-', $params['chronology_date'] ); + } + } + + if (isset($params['flat'])) + { + $url.= '/flat'; + } + + if (isset($params['start']) and $params['start'] > 0) + { + $url.= '/start-'.$params['start']; + } + return $url; +} + +/** + * return the section token of an index or picture URL. + * + * Depending on section, other parameters are required (see function code + * for details) + * + * @param array + * @return string + */ +function make_section_in_url($params) +{ + global $conf; + $section_string = ''; + + $section_of = array( + 'category' => 'categories', + 'tags' => 'tags', + 'list' => 'list', + 'search' => 'search', + ); + + foreach ($section_of as $param => $section) + { + if (isset($params[$param])) + { + $params['section'] = $section; + } + } + + if (!isset($params['section'])) + { + $params['section'] = 'none'; + } + + switch($params['section']) + { + case 'categories' : + { + if (!isset($params['category'])) + { + $section_string.= '/categories'; + } + else + { + is_array($params['category']) or trigger_error( + 'make_section_in_url wrong type for category', E_USER_WARNING + ); + is_numeric($params['category']['id']) or trigger_error( + 'make_section_in_url category id not numeric', E_USER_WARNING + ); + isset($params['category']['name']) or trigger_error( + 'make_section_in_url category name not set', E_USER_WARNING + ); + + array_key_exists('permalink', $params['category']) or trigger_error( + 'make_section_in_url category permalink not set', E_USER_WARNING + ); + + $section_string.= '/category/'; + if ( empty($params['category']['permalink']) ) + { + $section_string.= $params['category']['id']; + if ( $conf['category_url_style']=='id-name' ) + { + $section_string.= '-'.str2url($params['category']['name']); + } + } + else + { + $section_string.= $params['category']['permalink']; + } + } + + break; + } + case 'tags' : + { + if (!isset($params['tags']) or count($params['tags']) == 0) + { + die('make_section_in_url: require at least one tag'); + } + + $section_string.= '/tags'; + + foreach ($params['tags'] as $tag) + { + switch ( $conf['tag_url_style'] ) + { + case 'id': + $section_string.= '/'.$tag['id']; + break; + case 'tag': + if (isset($tag['url_name']) and !is_numeric($tag['url_name']) ) + { + $section_string.= '/'.$tag['url_name']; + break; + } + default: + $section_string.= '/'.$tag['id']; + if (isset($tag['url_name'])) + { + $section_string.= '-'.$tag['url_name']; + } + } + } + + break; + } + case 'search' : + { + if (!isset($params['search'])) + { + die('make_section_in_url: require a search identifier'); + } + + $section_string.= '/search/'.$params['search']; + + break; + } + case 'list' : + { + if (!isset($params['list'])) + { + die('make_section_in_url: require a list of items'); + } + + $section_string.= '/list/'.implode(',', $params['list']); + + break; + } + case 'none' : + { + break; + } + default : + { + $section_string.= '/'.$params['section']; + } + } + + return $section_string; +} + +/** + * the reverse of make_section_in_url + * returns the 'section' (categories/tags/...) and the data associated with it + * + * Depending on section, other parameters are returned (category/tags/list/...) + * + * @param array of url tokens to parse + * @param int the index in the array of url tokens; in/out + * @return array + */ +function parse_section_url( $tokens, &$next_token) +{ + $page=array(); + if (0 === strpos(@$tokens[$next_token], 'categor')) + { + $page['section'] = 'categories'; + $next_token++; + + if (isset($tokens[$next_token]) ) + { + if (preg_match('/^(\d+)(?:-(.+))?$/', $tokens[$next_token], $matches)) + { + if ( isset($matches[2]) ) + $page['hit_by']['cat_url_name'] = $matches[2]; + $page['category'] = $matches[1]; + $next_token++; + } + else + {// try a permalink + $maybe_permalinks = array(); + $current_token = $next_token; + while ( isset($tokens[$current_token]) + and strpos($tokens[$current_token], 'created-')!==0 + and strpos($tokens[$current_token], 'posted-')!==0 + and strpos($tokens[$next_token], 'start-')!==0 + and $tokens[$current_token] != 'flat') + { + if (empty($maybe_permalinks)) + { + array_push($maybe_permalinks, $tokens[$current_token]); + } + else + { + array_push($maybe_permalinks, + $maybe_permalinks[count($maybe_permalinks)-1] + . '/' . $tokens[$current_token] + ); + } + $current_token++; + } + + if ( count($maybe_permalinks) ) + { + $cat_id = get_cat_id_from_permalinks($maybe_permalinks, $perma_index); + if ( isset($cat_id) ) + { + $next_token += $perma_index+1; + $page['category'] = $cat_id; + $page['hit_by']['cat_permalink'] = $maybe_permalinks[$perma_index]; + } + else + { + page_not_found('Permalink for album not found'); + } + } + } + } + + if (isset($page['category'])) + { + $result = get_cat_info($page['category']); + if (empty($result)) + { + page_not_found('Requested category does not exist' ); + } + $page['category']=$result; + } + } + else if (0 === strpos(@$tokens[$next_token], 'tag')) + { + $page['section'] = 'tags'; + $page['tags'] = array(); + + $next_token++; + $i = $next_token; + + $requested_tag_ids = array(); + $requested_tag_url_names = array(); + + while (isset($tokens[$i])) + { + if ( preg_match('/^(created-|posted-|start-(\d)+)/', $tokens[$i]) ) + break; + + if ( preg_match('/^(\d+)(?:-(.*))?/', $tokens[$i], $matches) ) + { + array_push($requested_tag_ids, $matches[1]); + } + else + { + array_push($requested_tag_url_names, $tokens[$i]); + } + $i++; + } + $next_token = $i; + + if ( empty($requested_tag_ids) && empty($requested_tag_url_names) ) + { + bad_request('at least one tag required'); + } + + $page['tags'] = find_tags($requested_tag_ids, $requested_tag_url_names); + if ( empty($page['tags']) ) + { + page_not_found('Requested tag does not exist', get_root_url().'tags.php' ); + } + } + else if (0 === strpos(@$tokens[$next_token], 'fav')) + { + $page['section'] = 'favorites'; + $next_token++; + } + else if ('most_visited' == @$tokens[$next_token]) + { + $page['section'] = 'most_visited'; + $next_token++; + } + else if ('best_rated' == @$tokens[$next_token]) + { + $page['section'] = 'best_rated'; + $next_token++; + } + else if ('recent_pics' == @$tokens[$next_token]) + { + $page['section'] = 'recent_pics'; + $next_token++; + } + else if ('recent_cats' == @$tokens[$next_token]) + { + $page['section'] = 'recent_cats'; + $next_token++; + } + else if ('search' == @$tokens[$next_token]) + { + $page['section'] = 'search'; + $next_token++; + + preg_match('/(\d+)/', @$tokens[$next_token], $matches); + if (!isset($matches[1])) + { + bad_request('search identifier is missing'); + } + $page['search'] = $matches[1]; + $next_token++; + } + else if ('list' == @$tokens[$next_token]) + { + $page['section'] = 'list'; + $next_token++; + + $page['list'] = array(); + + // No pictures + if (empty($tokens[$next_token])) + { + // Add dummy element list + array_push($page['list'], -1); + } + // With pictures list + else + { + if (!preg_match('/^\d+(,\d+)*$/', $tokens[$next_token])) + { + bad_request('wrong format on list GET parameter'); + } + foreach (explode(',', $tokens[$next_token]) as $image_id) + { + array_push($page['list'], $image_id); + } + } + $next_token++; + } + return $page; +} + +/** + * the reverse of add_well_known_params_in_url + * parses start, flat and chronology from url tokens +*/ +function parse_well_known_params_url($tokens, &$i) +{ + $page = array(); + while (isset($tokens[$i])) + { + if (preg_match('/^start-(\d+)/', $tokens[$i], $matches)) + { + $page['start'] = $matches[1]; + } + + if ( 'flat' == $tokens[$i] ) + { + // indicate a special list of images + $page['flat'] = true; + } + + if (preg_match('/^(posted|created)/', $tokens[$i] )) + { + $chronology_tokens = explode('-', $tokens[$i] ); + + $page['chronology_field'] = $chronology_tokens[0]; + + array_shift($chronology_tokens); + $page['chronology_style'] = $chronology_tokens[0]; + + array_shift($chronology_tokens); + if ( count($chronology_tokens)>0 ) + { + if ('list'==$chronology_tokens[0] or + 'calendar'==$chronology_tokens[0]) + { + $page['chronology_view'] = $chronology_tokens[0]; + array_shift($chronology_tokens); + } + $page['chronology_date'] = $chronology_tokens; + } + } + $i++; + } + return $page; +} + +/** + * Indicate to build url with full path + * + * @param null + * @return null + */ +function set_make_full_url() +{ + global $page; + + if (!isset($page['save_root_path'])) + { + if (isset($page['root_path'])) + { + $page['save_root_path']['path'] = $page['root_path']; + } + $page['save_root_path']['count'] = 1; + $page['root_path'] = get_absolute_root_url(); + } + else + { + $page['save_root_path']['count'] += 1; + } +} + +/** + * Restore old parameter to build url with full path + * + * @param null + * @return null + */ +function unset_make_full_url() +{ + global $page; + + if (isset($page['save_root_path'])) + { + if ($page['save_root_path']['count'] == 1) + { + if (isset($page['save_root_path']['path'])) + { + $page['root_path'] = $page['save_root_path']['path']; + } + else + { + unset($page['root_path']); + } + unset($page['save_root_path']); + } + else + { + $page['save_root_path']['count'] -= 1; + } + } +} + +/** + * Embellish the url argument + * + * @param $url + * @return $url embellished + */ +function embellish_url($url) +{ + return str_replace('/./', '/', $url); +} + +?>
\ No newline at end of file diff --git a/BSF/include/functions_user.inc.php b/BSF/include/functions_user.inc.php new file mode 100644 index 000000000..d2c9530e2 --- /dev/null +++ b/BSF/include/functions_user.inc.php @@ -0,0 +1,1340 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// validate_mail_address: +// o verifies whether the given mail address has the +// right format. ie someone@domain.com "someone" can contain ".", "-" or +// even "_". Exactly as "domain". The extension doesn't have to be +// "com". The mail address can also be empty. +// o check if address could be empty +// o check if address is not used by a other user +// If the mail address doesn't correspond, an error message is returned. +// +function validate_mail_address($user_id, $mail_address) +{ + global $conf; + + if (empty($mail_address) and + !($conf['obligatory_user_mail_address'] and + in_array(script_basename(), array('register', 'profile')))) + { + return ''; + } + + $regex = '/^[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)*\.[a-z]+$/'; + if ( !preg_match( $regex, $mail_address ) ) + { + return l10n('reg_err_mail_address'); + } + + if (defined("PHPWG_INSTALLED") and !empty($mail_address)) + { + $query = ' +select count(*) +from '.USERS_TABLE.' +where upper('.$conf['user_fields']['email'].') = upper(\''.$mail_address.'\') +'.(is_numeric($user_id) ? 'and '.$conf['user_fields']['id'].' != \''.$user_id.'\'' : '').' +;'; + list($count) = mysql_fetch_array(pwg_query($query)); + if ($count != 0) + { + return l10n('reg_err_mail_address_dbl'); + } + } +} + +function register_user($login, $password, $mail_address, + $with_notification = true, $errors = array()) +{ + global $conf; + + if ($login == '') + { + array_push($errors, l10n('reg_err_login1')); + } + if (ereg("^.* $", $login)) + { + array_push($errors, l10n('reg_err_login2')); + } + if (ereg("^ .*$", $login)) + { + array_push($errors, l10n('reg_err_login3')); + } + if (get_userid($login)) + { + array_push($errors, l10n('reg_err_login5')); + } + $mail_error = validate_mail_address(null, $mail_address); + if ('' != $mail_error) + { + array_push($errors, $mail_error); + } + + $errors = trigger_event('register_user_check', + $errors, + array( + 'username'=>$login, + 'password'=>$password, + 'email'=>$mail_address, + ) + ); + + // if no error until here, registration of the user + if (count($errors) == 0) + { + // what will be the inserted id ? + $query = ' +SELECT MAX('.$conf['user_fields']['id'].') + 1 + FROM '.USERS_TABLE.' +;'; + list($next_id) = mysql_fetch_array(pwg_query($query)); + + $insert = + array( + $conf['user_fields']['id'] => $next_id, + $conf['user_fields']['username'] => mysql_escape_string($login), + $conf['user_fields']['password'] => $conf['pass_convert']($password), + $conf['user_fields']['email'] => $mail_address + ); + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + mass_inserts(USERS_TABLE, array_keys($insert), array($insert)); + + // Assign by default groups + { + $query = ' +SELECT id + FROM '.GROUPS_TABLE.' + WHERE is_default = \''.boolean_to_string(true).'\' + ORDER BY id ASC +;'; + $result = pwg_query($query); + + $inserts = array(); + while ($row = mysql_fetch_array($result)) + { + array_push + ( + $inserts, + array + ( + 'user_id' => $next_id, + 'group_id' => $row['id'] + ) + ); + } + } + + if (count($inserts) != 0) + { + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + mass_inserts(USER_GROUP_TABLE, array('user_id', 'group_id'), $inserts); + } + + create_user_infos($next_id); + + if ($with_notification and $conf['email_admin_on_new_user']) + { + include_once(PHPWG_ROOT_PATH.'include/functions_mail.inc.php'); + $admin_url = get_absolute_root_url() + .'admin.php?page=user_list&username='.$login; + + $keyargs_content = array + ( + get_l10n_args('User: %s', $login), + get_l10n_args('Email: %s', $_POST['mail_address']), + get_l10n_args('', ''), + get_l10n_args('Admin: %s', $admin_url) + ); + + pwg_mail_notification_admins + ( + get_l10n_args('Registration of %s', $login), + $keyargs_content + ); + } + + trigger_action('register_user', + array( + 'id'=>$next_id, + 'username'=>$login, + 'email'=>$mail_address, + ) + ); + } + + return $errors; +} + +function build_user( $user_id, $use_cache ) +{ + global $conf; + + $user['id'] = $user_id; + $user = array_merge( $user, getuserdata($user_id, $use_cache) ); + + if ($user['id'] == $conf['guest_id'] and $user['status'] <> 'guest') + { + $user['status'] = 'guest'; + $user['internal_status']['guest_must_be_guest'] = true; + } + + // calculation of the number of picture to display per page + $user['nb_image_page'] = $user['nb_image_line'] * $user['nb_line_page']; + + if (is_admin($user['status'])) + { + list($user['admin_template'], $user['admin_theme']) = + explode ('/', $conf['admin_layout']); + } + + list($user['template'], $user['theme']) = explode('/', $user['template']); + + return $user; +} + +/** + * find informations related to the user identifier + * + * @param int user identifier + * @param boolean use_cache + * @param array + */ +function getuserdata($user_id, $use_cache) +{ + global $conf; + + $userdata = array(); + + $query = ' +SELECT '; + $is_first = true; + foreach ($conf['user_fields'] as $pwgfield => $dbfield) + { + if ($is_first) + { + $is_first = false; + } + else + { + $query.= ' + , '; + } + $query.= $dbfield.' AS '.$pwgfield; + } + $query.= ' + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['id'].' = \''.$user_id.'\' +;'; + + $row = mysql_fetch_array(pwg_query($query)); + + while (true) + { + $query = ' +SELECT ui.*, uc.* + FROM '.USER_INFOS_TABLE.' AS ui LEFT JOIN '.USER_CACHE_TABLE.' AS uc + ON ui.user_id = uc.user_id + WHERE ui.user_id = \''.$user_id.'\' +;'; + $result = pwg_query($query); + if (mysql_num_rows($result) > 0) + { + break; + } + else + { + create_user_infos($user_id); + } + } + + $row = array_merge($row, mysql_fetch_array($result)); + + foreach ($row as $key => $value) + { + if (!is_numeric($key)) + { + // If the field is true or false, the variable is transformed into a + // boolean value. + if ($value == 'true' or $value == 'false') + { + $userdata[$key] = get_boolean($value); + } + else + { + $userdata[$key] = $value; + } + } + } + + if ($use_cache) + { + if (!isset($userdata['need_update']) + or !is_bool($userdata['need_update']) + or $userdata['need_update'] == true) + { + $userdata['forbidden_categories'] = + calculate_permissions($userdata['id'], $userdata['status']); + + /* now we build the list of forbidden images (this list does not contain + images that are not in at least an authorized category)*/ + $query = ' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON id=image_id + WHERE category_id NOT IN ('.$userdata['forbidden_categories'].') + AND level>'.$userdata['level']; + $forbidden_ids = array_from_query($query, 'id'); + + if ( empty($forbidden_ids) ) + { + array_push( $forbidden_ids, 0 ); + } + $userdata['image_access_type'] = 'NOT IN'; //TODO maybe later + $userdata['image_access_list'] = implode(',',$forbidden_ids); + + update_user_cache_categories($userdata); + + // Set need update are done + $userdata['need_update'] = false; + + // Indicate update done + $userdata['need_update_done'] = true; + + $query = ' +SELECT COUNT(DISTINCT(image_id)) as total + FROM '.IMAGE_CATEGORY_TABLE.' + WHERE category_id NOT IN ('.$userdata['forbidden_categories'].') + AND image_id '.$userdata['image_access_type'].' ('.$userdata['image_access_list'].') +;'; + list($userdata['nb_total_images']) = mysql_fetch_array(pwg_query($query)); + + // update user cache + $query = ' +DELETE FROM '.USER_CACHE_TABLE.' + WHERE user_id = '.$userdata['id'].' +;'; + pwg_query($query); + + $query = ' +INSERT INTO '.USER_CACHE_TABLE.' + (user_id, need_update, forbidden_categories, nb_total_images, + image_access_type, image_access_list) + VALUES + ('.$userdata['id'].',\''.boolean_to_string($userdata['need_update']).'\',\'' + .$userdata['forbidden_categories'].'\','.$userdata['nb_total_images'].',"' + .$userdata['image_access_type'].'","'.$userdata['image_access_list'].'") +;'; + pwg_query($query); + } + else + { + // Indicate update not done + $userdata['need_update_done'] = false; + } + } + + return $userdata; +} + +/* + * deletes favorites of the current user if he's not allowed to see them + * + * @return void + */ +function check_user_favorites() +{ + global $user; + + if ($user['forbidden_categories'] == '') + { + return; + } + + // $filter['visible_categories'] and $filter['visible_images'] + // must be not used because filter <> restriction + // retrieving images allowed : belonging to at least one authorized + // category + $query = ' +SELECT DISTINCT f.image_id + FROM '.FAVORITES_TABLE.' AS f INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic + ON f.image_id = ic.image_id + WHERE f.user_id = '.$user['id'].' +'.get_sql_condition_FandF + ( + array + ( + 'forbidden_categories' => 'ic.category_id', + ), + 'AND' + ).' +;'; + $result = pwg_query($query); + $authorizeds = array(); + while ($row = mysql_fetch_array($result)) + { + array_push($authorizeds, $row['image_id']); + } + + $query = ' +SELECT image_id + FROM '.FAVORITES_TABLE.' + WHERE user_id = '.$user['id'].' +;'; + $result = pwg_query($query); + $favorites = array(); + while ($row = mysql_fetch_array($result)) + { + array_push($favorites, $row['image_id']); + } + + $to_deletes = array_diff($favorites, $authorizeds); + + if (count($to_deletes) > 0) + { + $query = ' +DELETE FROM '.FAVORITES_TABLE.' + WHERE image_id IN ('.implode(',', $to_deletes).') + AND user_id = '.$user['id'].' +;'; + pwg_query($query); + } +} + +/** + * calculates the list of forbidden categories for a given user + * + * Calculation is based on private categories minus categories authorized to + * the groups the user belongs to minus the categories directly authorized + * to the user. The list contains at least -1 to be compliant with queries + * such as "WHERE category_id NOT IN ($forbidden_categories)" + * + * @param int user_id + * @param string user_status + * @return string forbidden_categories + */ +function calculate_permissions($user_id, $user_status) +{ + $private_array = array(); + $authorized_array = array(); + + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE status = \'private\' +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($private_array, $row['id']); + } + + // retrieve category ids directly authorized to the user + $query = ' +SELECT cat_id + FROM '.USER_ACCESS_TABLE.' + WHERE user_id = '.$user_id.' +;'; + $authorized_array = array_from_query($query, 'cat_id'); + + // retrieve category ids authorized to the groups the user belongs to + $query = ' +SELECT cat_id + FROM '.USER_GROUP_TABLE.' AS ug INNER JOIN '.GROUP_ACCESS_TABLE.' AS ga + ON ug.group_id = ga.group_id + WHERE ug.user_id = '.$user_id.' +;'; + $authorized_array = + array_merge( + $authorized_array, + array_from_query($query, 'cat_id') + ); + + // uniquify ids : some private categories might be authorized for the + // groups and for the user + $authorized_array = array_unique($authorized_array); + + // only unauthorized private categories are forbidden + $forbidden_array = array_diff($private_array, $authorized_array); + + // if user is not an admin, locked categories are forbidden + if (!is_admin($user_status)) + { + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE visible = \'false\' +;'; + $result = pwg_query($query); + while ($row = mysql_fetch_array($result)) + { + array_push($forbidden_array, $row['id']); + } + $forbidden_array = array_unique($forbidden_array); + } + + if ( empty($forbidden_array) ) + {// at least, the list contains 0 value. This category does not exists so + // where clauses such as "WHERE category_id NOT IN(0)" will always be + // true. + array_push($forbidden_array, 0); + } + + return implode(',', $forbidden_array); +} + +/** + * compute data of categories branches (one branch only) + */ +function compute_branch_cat_data(&$cats, &$list_cat_id, &$level, &$ref_level) +{ + $date = ''; + $count_images = 0; + $count_categories = 0; + do + { + $cat_id = array_pop($list_cat_id); + if (!is_null($cat_id)) + { + // Count images and categories + $cats[$cat_id]['count_images'] += $count_images; + $cats[$cat_id]['count_categories'] += $count_categories; + $count_images = $cats[$cat_id]['count_images']; + $count_categories = $cats[$cat_id]['count_categories'] + 1; + + if ((empty($cats[$cat_id]['max_date_last'])) or ($cats[$cat_id]['max_date_last'] < $date)) + { + $cats[$cat_id]['max_date_last'] = $date; + } + else + { + $date = $cats[$cat_id]['max_date_last']; + } + $ref_level = substr_count($cats[$cat_id]['global_rank'], '.') + 1; + } + else + { + $ref_level = 0; + } + } while ($level <= $ref_level); + + // Last cat updating must be added to list for next branch + if ($ref_level <> 0) + { + array_push($list_cat_id, $cat_id); + } +} + +/** + * compute data of categories branches + */ +function compute_categories_data(&$cats) +{ + $ref_level = 0; + $level = 0; + $list_cat_id = array(); + + foreach ($cats as $id => $category) + { + // Compute + $level = substr_count($category['global_rank'], '.') + 1; + if ($level > $ref_level) + { + array_push($list_cat_id, $id); + } + else + { + compute_branch_cat_data($cats, $list_cat_id, $level, $ref_level); + array_push($list_cat_id, $id); + } + $ref_level = $level; + } + + $level = 1; + compute_branch_cat_data($cats, $list_cat_id, $level, $ref_level); +} + +/** + * get computed array of categories + * + * @param array userdata + * @param int filter_days number of recent days to filter on or null + * @return array + */ +function get_computed_categories($userdata, $filter_days=null) +{ + $query = 'SELECT c.id cat_id, global_rank'; + // Count by date_available to avoid count null + $query .= ', + MAX(date_available) date_last, COUNT(date_available) nb_images +FROM '.CATEGORIES_TABLE.' as c + LEFT JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON ic.category_id = c.id + LEFT JOIN '.IMAGES_TABLE.' AS i + ON ic.image_id = i.id + AND i.level<='.$userdata['level']; + + if ( isset($filter_days) ) + { + $query .= ' AND i.date_available > SUBDATE(CURRENT_DATE,INTERVAL '.$filter_days.' DAY)'; + } + + if ( !empty($userdata['forbidden_categories']) ) + { + $query.= ' + WHERE c.id NOT IN ('.$userdata['forbidden_categories'].')'; + } + + $query.= ' + GROUP BY c.id'; + + $result = pwg_query($query); + + $cats = array(); + while ($row = mysql_fetch_assoc($result)) + { + $row['user_id'] = $userdata['id']; + $row['count_categories'] = 0; + $row['count_images'] = (int)$row['nb_images']; + $row['max_date_last'] = $row['date_last']; + + $cats += array($row['cat_id'] => $row); + } + usort($cats, 'global_rank_compare'); + + compute_categories_data($cats); + + if ( isset($filter_days) ) + { + $cat_tmp = $cats; + $cats = array(); + + foreach ($cat_tmp as $category) + { + if (!empty($category['max_date_last'])) + { + // Re-init counters + $category['count_categories'] = 0; + $category['count_images'] = (int)$category['nb_images']; + // Keep category + $cats[$category['cat_id']] = $category; + } + } + // Compute a second time + compute_categories_data($cats); + } + return $cats; +} + +/** + * update data of user_cache_categories + * + * @param array userdata + * @return null + */ +function update_user_cache_categories($userdata) +{ + // delete user cache + $query = ' +DELETE FROM '.USER_CACHE_CATEGORIES_TABLE.' + WHERE user_id = '.$userdata['id'].' +;'; + pwg_query($query); + + $cats = get_computed_categories($userdata, null); + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + mass_inserts + ( + USER_CACHE_CATEGORIES_TABLE, + array + ( + 'user_id', 'cat_id', + 'date_last', 'max_date_last', 'nb_images', 'count_images', 'count_categories' + ), + $cats + ); +} + +/** + * returns the username corresponding to the given user identifier if exists + * + * @param int user_id + * @return mixed + */ +function get_username($user_id) +{ + global $conf; + + $query = ' +SELECT '.$conf['user_fields']['username'].' + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['id'].' = '.intval($user_id).' +;'; + $result = pwg_query($query); + if (mysql_num_rows($result) > 0) + { + list($username) = mysql_fetch_row($result); + } + else + { + return false; + } + + return $username; +} + +/** + * returns user identifier thanks to his name, false if not found + * + * @param string username + * @param int user identifier + */ +function get_userid($username) +{ + global $conf; + + $username = mysql_escape_string($username); + + $query = ' +SELECT '.$conf['user_fields']['id'].' + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['username'].' = \''.$username.'\' +;'; + $result = pwg_query($query); + + if (mysql_num_rows($result) == 0) + { + return false; + } + else + { + list($user_id) = mysql_fetch_row($result); + return $user_id; + } +} + +/** + * search an available feed_id + * + * @return string feed identifier + */ +function find_available_feed_id() +{ + while (true) + { + $key = generate_key(50); + $query = ' +SELECT COUNT(*) + FROM '.USER_FEED_TABLE.' + WHERE id = \''.$key.'\' +;'; + list($count) = mysql_fetch_row(pwg_query($query)); + if (0 == $count) + { + return $key; + } + } +} + +/* + * Returns a array with default user value + * + * @param convert_str allows to convert string value if necessary + */ +function get_default_user_info($convert_str = true) +{ + global $page, $conf; + + if (!isset($page['cache_default_user'])) + { + $query = 'select * from '.USER_INFOS_TABLE. + ' where user_id = '.$conf['default_user_id'].';'; + + $result = pwg_query($query); + $page['cache_default_user'] = mysql_fetch_assoc($result); + + if ($page['cache_default_user'] !== false) + { + unset($page['cache_default_user']['user_id']); + unset($page['cache_default_user']['status']); + unset($page['cache_default_user']['registration_date']); + } + } + + if (is_array($page['cache_default_user']) and $convert_str) + { + $default_user = array(); + foreach ($page['cache_default_user'] as $name => $value) + { + // If the field is true or false, the variable is transformed into a + // boolean value. + if ($value == 'true' or $value == 'false') + { + $default_user[$name] = get_boolean($value); + } + else + { + $default_user[$name] = $value; + } + } + return $default_user; + } + else + { + return $page['cache_default_user']; + } +} + +/* + * Returns a default user value + * + * @param value_name: name of value + * @param sos_value: value used if don't exist value + */ +function get_default_user_value($value_name, $sos_value) +{ + $default_user = get_default_user_info(true); + if ($default_user === false or !isset($default_user[$value_name])) + { + return $sos_value; + } + else + { + return $default_user[$value_name]; + } +} + +/* + * Returns the default template value + * + */ +function get_default_template() +{ + return get_default_user_value('template', PHPWG_DEFAULT_TEMPLATE); +} + +/* + * Returns the default language value + * + */ +function get_default_language() +{ + return get_default_user_value('language', PHPWG_DEFAULT_LANGUAGE); +} + +/** + * add user informations based on default values + * + * @param int user_id / array of user_if + * @param array of values used to override default user values + */ +function create_user_infos($arg_id, $override_values = null) +{ + global $conf; + + if (is_array($arg_id)) + { + $user_ids = $arg_id; + } + else + { + $user_ids = array(); + if (is_numeric($arg_id)) + { + $user_ids[] = $arg_id; + } + } + + if (!empty($user_ids)) + { + $inserts = array(); + list($dbnow) = mysql_fetch_row(pwg_query('SELECT NOW();')); + + $default_user = get_default_user_info(false); + if ($default_user === false) + { + // Default on structure are used + $default_user = array(); + } + + if (!is_null($override_values)) + { + $default_user = array_merge($default_user, $override_values); + } + + foreach ($user_ids as $user_id) + { + $level= isset($default_user['level']) ? $default_user['level'] : 0; + if ($user_id == $conf['webmaster_id']) + { + $status = 'webmaster'; + $level = max( $conf['available_permission_levels'] ); + } + else if (($user_id == $conf['guest_id']) or + ($user_id == $conf['default_user_id'])) + { + $status = 'guest'; + } + else + { + $status = 'normal'; + } + + $insert = array_merge( + $default_user, + array( + 'user_id' => $user_id, + 'status' => $status, + 'registration_date' => $dbnow, + 'level' => $level + )); + + array_push($inserts, $insert); + } + + include_once(PHPWG_ROOT_PATH.'admin/include/functions.php'); + mass_inserts(USER_INFOS_TABLE, array_keys($inserts[0]), $inserts); + + } +} + +/** + * returns the groupname corresponding to the given group identifier if + * exists + * + * @param int group_id + * @return mixed + */ +function get_groupname($group_id) +{ + $query = ' +SELECT name + FROM '.GROUPS_TABLE.' + WHERE id = '.intval($group_id).' +;'; + $result = pwg_query($query); + if (mysql_num_rows($result) > 0) + { + list($groupname) = mysql_fetch_row($result); + } + else + { + return false; + } + + return $groupname; +} + + +/** + * returns the auto login key or false on error + * @param int user_id + * @param string [out] username +*/ +function calculate_auto_login_key($user_id, &$username) +{ + global $conf; + $query = ' +SELECT '.$conf['user_fields']['username'].' AS username + , '.$conf['user_fields']['password'].' AS password +FROM '.USERS_TABLE.' +WHERE '.$conf['user_fields']['id'].' = '.$user_id; + $result = pwg_query($query); + if (mysql_num_rows($result) > 0) + { + $row = mysql_fetch_assoc($result); + $username = $row['username']; + $data = $row['username'].$row['password']; + $key = base64_encode( + pack('H*', sha1($data)) + .hash_hmac('md5', $data, $conf['secret_key'],true) + ); + return $key; + } + return false; +} + +/* + * Performs all required actions for user login + * @param int user_id + * @param bool remember_me + * @return void +*/ +function log_user($user_id, $remember_me) +{ + global $conf, $user; + + if ($remember_me and $conf['authorize_remembering']) + { + $key = calculate_auto_login_key($user_id, $username); + if ($key!==false) + { + $cookie = array('id' => (int)$user_id, 'key' => $key); + setcookie($conf['remember_me_name'], + serialize($cookie), + time()+$conf['remember_me_length'], + cookie_path() + ); + } + } + else + { // make sure we clean any remember me ... + setcookie($conf['remember_me_name'], '', 0, cookie_path()); + } + if ( session_id()!="" ) + { // we regenerate the session for security reasons + // see http://www.acros.si/papers/session_fixation.pdf + session_regenerate_id(); + } + else + { + session_start(); + } + $_SESSION['pwg_uid'] = (int)$user_id; + + $user['id'] = $_SESSION['pwg_uid']; +} + +/* + * Performs auto-connexion when cookie remember_me exists + * @return true/false +*/ +function auto_login() { + global $conf; + + if ( isset( $_COOKIE[$conf['remember_me_name']] ) ) + { + $cookie = unserialize(stripslashes($_COOKIE[$conf['remember_me_name']])); + if ($cookie!==false and is_numeric(@$cookie['id']) ) + { + $key = calculate_auto_login_key( $cookie['id'], $username ); + if ($key!==false and $key===$cookie['key']) + { + log_user($cookie['id'], true); + trigger_action('login_success', $username); + return true; + } + } + setcookie($conf['remember_me_name'], '', 0, cookie_path()); + } + return false; +} + +/** + * Tries to login a user given username and password (must be MySql escaped) + * return true on success + */ +function try_log_user($username, $password, $remember_me) +{ + global $conf; + // retrieving the encrypted password of the login submitted + $query = ' +SELECT '.$conf['user_fields']['id'].' AS id, + '.$conf['user_fields']['password'].' AS password + FROM '.USERS_TABLE.' + WHERE '.$conf['user_fields']['username'].' = \''.$username.'\' +;'; + $row = mysql_fetch_assoc(pwg_query($query)); + if ($row['password'] == $conf['pass_convert']($password)) + { + log_user($row['id'], $remember_me); + trigger_action('login_success', $username); + return true; + } + trigger_action('login_failure', $username); + return false; +} + +/* + * Return user status used in this library + * @return string +*/ +function get_user_status($user_status) +{ + global $user; + + if (empty($user_status)) + { + if (isset($user['status'])) + { + $user_status = $user['status']; + } + else + { + // swicth to default value + $user_status = ''; + } + } + return $user_status; +} + +/* + * Return access_type definition of user + * Test does with user status + * @return bool +*/ +function get_access_type_status($user_status='') +{ + global $conf; + + switch (get_user_status($user_status)) + { + case 'guest': + { + $access_type_status = + ($conf['guest_access'] ? ACCESS_GUEST : ACCESS_FREE); + break; + } + case 'generic': + { + $access_type_status = ACCESS_GUEST; + break; + } + case 'normal': + { + $access_type_status = ACCESS_CLASSIC; + break; + } + case 'admin': + { + $access_type_status = ACCESS_ADMINISTRATOR; + break; + } + case 'webmaster': + { + $access_type_status = ACCESS_WEBMASTER; + break; + } + default: + { + $access_type_status = ACCESS_FREE; + break; + } + } + + return $access_type_status; +} + +/* + * Return if user have access to access_type definition + * Test does with user status + * @return bool +*/ +function is_autorize_status($access_type, $user_status = '') +{ + return (get_access_type_status($user_status) >= $access_type); +} + +/* + * Check if user have access to access_type definition + * Stop action if there are not access + * Test does with user status + * @return none +*/ +function check_status($access_type, $user_status = '') +{ + if (!is_autorize_status($access_type, $user_status)) + { + access_denied(); + } +} + +/* + * Return if user is generic + * @return bool +*/ + function is_generic($user_status = '') +{ + return get_user_status($user_status) == 'generic'; +} + +/* + * Return if user is only a guest + * @return bool +*/ + function is_a_guest($user_status = '') +{ + return get_user_status($user_status) == 'guest'; +} + +/* + * Return if user is, at least, a classic user + * @return bool +*/ + function is_classic_user($user_status = '') +{ + return is_autorize_status(ACCESS_CLASSIC, $user_status); +} + +/* + * Return if user is, at least, an administrator + * @return bool +*/ + function is_admin($user_status = '') +{ + return is_autorize_status(ACCESS_ADMINISTRATOR, $user_status); +} + +/* + * Return if current user is an adviser + * @return bool +*/ +function is_adviser() +{ + global $user; + + return ($user['adviser'] == 'true'); +} + +/* + * Return mail address as display text + * @return string +*/ +function get_email_address_as_display_text($email_address) +{ + global $conf; + + if (!isset($email_address) or (trim($email_address) == '')) + { + return ''; + } + else + { + if (defined('IN_ADMIN') and is_adviser()) + { + return 'adviser.mode@'.$_SERVER['SERVER_NAME']; + } + else + { + return $email_address; + } + } +} + +/* + * Compute sql where condition with restrict and filter data. "FandF" means + * Forbidden and Filters. + * + * @param array condition_fields: read function body + * @param string prefix_condition: prefixes sql if condition is not empty + * @param boolean force_one_condition: use at least "1 = 1" + * + * @return string sql where/conditions + */ +function get_sql_condition_FandF( + $condition_fields, + $prefix_condition = null, + $force_one_condition = false + ) +{ + global $user, $filter; + + $sql_list = array(); + + foreach ($condition_fields as $condition => $field_name) + { + switch($condition) + { + case 'forbidden_categories': + { + if (!empty($user['forbidden_categories'])) + { + $sql_list[] = + $field_name.' NOT IN ('.$user['forbidden_categories'].')'; + } + break; + } + case 'visible_categories': + { + if (!empty($filter['visible_categories'])) + { + $sql_list[] = + $field_name.' IN ('.$filter['visible_categories'].')'; + } + break; + } + case 'visible_images': + if (!empty($filter['visible_images'])) + { + $sql_list[] = + $field_name.' IN ('.$filter['visible_images'].')'; + } + // note there is no break - visible include forbidden + case 'forbidden_images': + if ( + !empty($user['image_access_list']) + or $user['image_access_type']!='NOT IN' + ) + { + $table_prefix=null; + if ($field_name=='id') + { + $table_prefix = ''; + } + elseif ($field_name=='i.id') + { + $table_prefix = 'i.'; + } + if ( isset($table_prefix) ) + { + $sql_list[]=$table_prefix.'level<='.$user['level']; + } + else + { + $sql_list[]=$field_name.' '.$user['image_access_type'] + .' ('.$user['image_access_list'].')'; + } + } + break; + default: + { + die('Unknow condition'); + break; + } + } + } + + if (count($sql_list) > 0) + { + $sql = '('.implode(' AND ', $sql_list).')'; + } + else + { + if ($force_one_condition) + { + $sql = '1 = 1'; + } + else + { + $sql = ''; + } + } + + if (isset($prefix_condition) and !empty($sql)) + { + $sql = $prefix_condition.' '.$sql; + } + + return $sql; +} + +?>
\ No newline at end of file diff --git a/BSF/include/functions_xml.inc.php b/BSF/include/functions_xml.inc.php new file mode 100644 index 000000000..1a849d434 --- /dev/null +++ b/BSF/include/functions_xml.inc.php @@ -0,0 +1,141 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ +define( 'ATT_REG', '\w+' ); +define( 'VAL_REG', '[^"]*' ); + +//------------------------------------------------------------------- functions +// getContent returns the content of a tag +// +// example : getContent( "<name>Joe</name>" ) returns "Joe" +// +// It also works with strings containing themself sub-tags : +// <perso><name>Jean</name><firstname>Billie</fisrtname></perso> -> +// <name>Jean</name><firstname>Billie</firstname> +function getContent( $element ) +{ + // deleting start of the tag + $content = preg_replace( '/^<[^>]+>/', '', $element ); + // deleting end of the tag + $content = preg_replace( '/<\/[^>]+>$/', '', $content ); + // replacing multiple instance of space character + $content = preg_replace( '/\s+/', ' ', $content ); + + return $content; +} + +// The function get Attribute returns the value corresponding to the +// attribute $attribute for the tag $element. +function getAttribute( $element, $attribute ) +{ +// echo htmlentities($element).'<br /><br />'; + $regex = '/^<\w+[^>]*\b'.$attribute.'\s*=\s*"('.VAL_REG.')"/i'; + if ( preg_match( $regex, $element, $out ) ) + { + return html_entity_decode($out[1], ENT_QUOTES); + } + else return ''; +} + +// The function encode Attribute returns the xml attribute $attribute="$value" +function encodeAttribute( $attribute, $value ) +{ + return $attribute.'="'.htmlspecialchars($value, ENT_QUOTES).'" '; +} + +// The function getChild returns the first child +// exemple : getChild( "<table><tr>XXX</tr><tr>YYY</tr></table>", "tr" ) +// returns "<tr>XXX</tr>" +function getChild( $document, $node ) +{ + $regex = '/<'.$node.'(\s+'.ATT_REG.'="'.VAL_REG.'")*'; + $regex.= '(\s*\/>|>.*<\/'.$node.'>)/U'; + + if + ( + preg_match( $regex, $document, $out ) + or + preg_last_error() == PREG_NO_ERROR + ) + { + return $out[0]; + } + else + { + die('getChild: error ['.preg_last_error().'] with preg_match function'); + } +} + +// getChildren returns a list of the children identified by the $node +// example : +// getChild( "<table><tr>XXX</tr><tr>YYY</tr></table>", "tr" ) +// returns an array with : +// $array[0] equals "<tr>XXX</tr>" +// $array[1] equals "<tr>YYY</tr>" +function getChildren( $document, $node ) +{ + $regex = '/<'.$node.'(\s+'.ATT_REG.'="'.VAL_REG.'")*'; + $regex.= '(\s*\/>|>.*<\/'.$node.'>)/U'; + + if + ( + preg_match_all( $regex, $document, $out ) + or + preg_last_error() == PREG_NO_ERROR + ) + { + return $out[0]; + } + else + { + die('getChild: error ['.preg_last_error().'] with preg_match_all function'); + } +} + +// get_CodeXML places the content of a text file in a PHP variable and +// return it. If the file can't be opened, returns false. +function getXmlCode( $filename ) +{ + if (function_exists('ini_set')) + { + // limit must be growed with php5 and "big" listing file + ini_set("pcre.backtrack_limit", pow(2, 32)); + } + + $file = fopen( $filename, 'r' ); + if ( !$file ) + { + return false; + } + + $xml_content = ''; + while ( !feof( $file ) ) + { + $xml_content .= fgets( $file, 1024 ); + } + fclose( $file ); + $xml_content = str_replace( "\n", '', $xml_content ); + $xml_content = str_replace( "\t", '', $xml_content ); + + return $xml_content; +} +?> diff --git a/BSF/include/index.php b/BSF/include/index.php new file mode 100644 index 000000000..c15b15795 --- /dev/null +++ b/BSF/include/index.php @@ -0,0 +1,30 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// Recursive call +$url = '../'; +header( 'Request-URI: '.$url ); +header( 'Content-Location: '.$url ); +header( 'Location: '.$url ); +exit(); +?> diff --git a/BSF/include/menubar.inc.php b/BSF/include/menubar.inc.php new file mode 100644 index 000000000..03e941226 --- /dev/null +++ b/BSF/include/menubar.inc.php @@ -0,0 +1,311 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * This file is included by the main page to show the menu bar + * + */ +$template->set_filenames( + array( + 'menubar' => 'menubar.tpl', + ) + ); + +trigger_action('loc_begin_menubar'); + +$template->assign( + array( + 'NB_PICTURE' => $user['nb_total_images'], + 'MENU_CATEGORIES_CONTENT' => get_categories_menu(), + 'U_CATEGORIES' => make_index_url(array('section' => 'categories')), + 'U_LOST_PASSWORD' => get_root_url().'password.php', + 'U_UPLOAD' => get_upload_menu_link() + ) + ); + +//-------------------------------------------------------------- external links +foreach ($conf['links'] as $url => $url_data) +{ + if (!is_array($url_data)) + { + $url_data = array('label' => $url_data); + } + + if + ( + (!isset($url_data['eval_visible'])) + or + (eval($url_data['eval_visible'])) + ) + { + $tpl_var = array( + 'URL' => $url, + 'LABEL' => $url_data['label'] + ); + + if (!isset($url_data['new_window']) or $url_data['new_window']) + { + $tpl_var['new_window'] = + array( + 'NAME' => (isset($url_data['nw_name']) ? $url_data['nw_name'] : ''), + 'FEATURES' => (isset($url_data['nw_features']) ? $url_data['nw_features'] : '') + ); + } + $template->append('links', $tpl_var); + } +} + +//------------------------------------------------------------------------ filter +if (!empty($conf['filter_pages']) and get_filter_page_value('used')) +{ + if ($filter['enabled']) + { + $template->assign( + 'U_STOP_FILTER', + add_url_params(make_index_url(array()), array('filter' => 'stop')) + ); + } + else + { + $template->assign( + 'U_START_FILTER', + add_url_params(make_index_url(array()), array('filter' => 'start-recent-'.$user['recent_period'])) + ); + } +} + +//------------------------------------------------------------------------ tags +if ('tags' == @$page['section']) +{ + // display tags associated to currently tagged items, less current tags + $tags = array(); + if ( !empty($page['items']) ) + { + $tags = get_common_tags($page['items'], + $conf['menubar_tag_cloud_items_number'], $page['tag_ids']); + } + + $tags = add_level_to_tags($tags); + + foreach ($tags as $tag) + { + $template->append( + 'related_tags', + array( + 'U_TAG' => make_index_url( + array( + 'tags' => array($tag) + ) + ), + + 'NAME' => $tag['name'], + + 'CLASS' => 'tagLevel'.$tag['level'], + + 'add' => array( + + 'URL' => make_index_url( + array( + 'tags' => array_merge( + $page['tags'], + array($tag) + ) + ) + ), + 'COUNTER' => $tag['counter'], + ) + ) + ); + } +} +//---------------------------------------------------------- special categories +// favorites categories +if ( !is_a_guest() ) +{ + $template->append( + 'special_categories', + array( + 'URL' => make_index_url(array('section' => 'favorites')), + 'TITLE' => l10n('favorite_cat_hint'), + 'NAME' => l10n('favorite_cat') + )); +} +// most visited +$template->append( + 'special_categories', + array( + 'URL' => make_index_url(array('section' => 'most_visited')), + 'TITLE' => l10n('most_visited_cat_hint'), + 'NAME' => l10n('most_visited_cat') + )); +// best rated +if ($conf['rate']) +{ + $template->append( + 'special_categories', + array( + 'URL' => make_index_url(array('section' => 'best_rated')), + 'TITLE' => l10n('best_rated_cat_hint'), + 'NAME' => l10n('best_rated_cat') + ) + ); +} +// random +$template->append( + 'special_categories', + array( + 'URL' => get_root_url().'random.php', + 'TITLE' => l10n('random_cat_hint'), + 'NAME' => l10n('random_cat'), + 'REL'=> 'rel="nofollow"' + )); + +// recent pics +$template->append( + 'special_categories', + array( + 'URL' => make_index_url(array('section' => 'recent_pics')), + 'TITLE' => l10n('recent_pics_cat_hint'), + 'NAME' => l10n('recent_pics_cat'), + )); +// recent cats +$template->append( + 'special_categories', + array( + 'URL' => make_index_url(array('section' => 'recent_cats')), + 'TITLE' => l10n('recent_cats_cat_hint'), + 'NAME' => l10n('recent_cats_cat'), + )); + +// calendar +$template->append( + 'special_categories', + array( + 'URL' => + make_index_url( + array( + 'chronology_field' => ($conf['calendar_datefield']=='date_available' + ? 'posted' : 'created'), + 'chronology_style'=> 'monthly', + 'chronology_view' => 'calendar' + ) + ), + 'TITLE' => l10n('calendar_hint'), + 'NAME' => l10n('calendar'), + 'REL'=> 'rel="nofollow"' + ) + ); +//--------------------------------------------------------------------- summary + +if (is_a_guest()) +{ + $template->assign( + array( + 'U_IDENTIFY' => get_root_url().'identification.php', + 'AUTHORIZE_REMEMBERING' => $conf['authorize_remembering'] + ) + ); + + if ($conf['allow_user_registration']) + { + $template->assign( 'U_REGISTER', get_root_url().'register.php'); + } +} +else +{ + $template->assign('USERNAME', $user['username']); + + if (is_autorize_status(ACCESS_CLASSIC)) + { + $template->assign('U_PROFILE', get_root_url().'profile.php'); + } + + // the logout link has no meaning with Apache authentication : it is not + // possible to logout with this kind of authentication. + if (!$conf['apache_authentication']) + { + $template->assign('U_LOGOUT', get_root_url().'?act=logout'); + } + + if (is_admin()) + { + $template->assign('U_ADMIN', get_root_url().'admin.php'); + } +} + +// tags link +$template->append( + 'summaries', + array( + 'TITLE' => l10n('See available tags'), + 'NAME' => l10n('Tags'), + 'U_SUMMARY'=> get_root_url().'tags.php', + ) + ); + +// search link +$template->append( + 'summaries', + array( + 'TITLE'=>l10n('hint_search'), + 'NAME'=>l10n('Search'), + 'U_SUMMARY'=> get_root_url().'search.php', + 'REL'=> 'rel="search"' + ) + ); + +// comments link +$template->append( + 'summaries', + array( + 'TITLE'=>l10n('hint_comments'), + 'NAME'=>l10n('comments'), + 'U_SUMMARY'=> get_root_url().'comments.php', + ) + ); + +// about link +$template->append( + 'summaries', + array( + 'TITLE' => l10n('about_page_title'), + 'NAME' => l10n('About'), + 'U_SUMMARY' => get_root_url().'about.php', + ) + ); + +// notification +$template->append( + 'summaries', + array( + 'TITLE'=>l10n('RSS feed'), + 'NAME'=>l10n('Notification'), + 'U_SUMMARY'=> get_root_url().'notification.php', + 'REL'=> 'rel="nofollow"' + ) + ); + +trigger_action('loc_end_menubar'); +$template->assign_var_from_handle('MENUBAR', 'menubar'); + +?> diff --git a/BSF/include/page_header.php b/BSF/include/page_header.php new file mode 100644 index 000000000..102e2bdd8 --- /dev/null +++ b/BSF/include/page_header.php @@ -0,0 +1,90 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// +// Start output of page +// +$template->set_filenames(array('header'=>'header.tpl')); + +trigger_action('loc_begin_page_header'); + +$template->assign( + array( + 'GALLERY_TITLE' => + isset($page['gallery_title']) ? + $page['gallery_title'] : $conf['gallery_title'], + + 'PAGE_BANNER' => + trigger_event('render_page_banner', + isset($page['page_banner']) ? + $page['page_banner'] : $conf['page_banner']), + + 'BODY_ID' => + isset($page['body_id']) ? + $page['body_id'] : '', + + 'CONTENT_ENCODING' => get_pwg_charset(), + 'PAGE_TITLE' => strip_tags($title), + 'LANG'=>$lang_info['code'], + 'DIR'=>$lang_info['direction'], + + 'U_HOME' => make_index_url(), + )); + + +// Header notes +if ( !empty($header_notes) ) +{ + $template->assign('header_notes',$header_notes); +} + +if ( !empty($page['meta_robots']) ) +{ + $template->append('head_elements', + '<meta name="robots" content="' + .implode(',', array_keys($page['meta_robots'])) + .'">' + ); +} + +// refresh +if ( isset( $refresh ) and intval($refresh) >= 0 + and isset( $url_link ) and isset( $redirect_msg ) ) +{ + $template->assign( + array( + 'REDIRECT_MSG' => $redirect_msg, + 'page_refresh' => array( + 'TIME' => $refresh, + 'U_REFRESH' => $url_link + ) + )); +} + +trigger_action('loc_end_page_header'); + +header('Content-Type: text/html; charset='.get_pwg_charset()); +$template->parse('header'); + +trigger_action('loc_after_page_header'); +?>
\ No newline at end of file diff --git a/BSF/include/page_tail.php b/BSF/include/page_tail.php new file mode 100644 index 000000000..670d23a2e --- /dev/null +++ b/BSF/include/page_tail.php @@ -0,0 +1,74 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ +$template->set_filenames(array('tail'=>'footer.tpl')); + +trigger_action('loc_begin_page_tail'); + +$template->assign( + array( + 'VERSION' => $conf['show_version'] ? PHPWG_VERSION : '', + 'PHPWG_URL' => PHPWG_URL, + )); + +//--------------------------------------------------------------------- contact + +if (!is_a_guest()) +{ + $template->assign( + 'CONTACT_MAIL', get_webmaster_mail_address() + ); +} + +//------------------------------------------------------------- generation time +$debug_vars = array(); + +if ($conf['show_queries']) +{ + $debug_vars = array_merge($debug_vars, array('QUERIES_LIST' => $debug) ); +} + +if ($conf['show_gt']) +{ + if (!isset($page['count_queries'])) + { + $page['count_queries'] = 0; + $page['queries_time'] = 0; + } + $time = get_elapsed_time($t2, get_moment()); + + $debug_vars = array_merge($debug_vars, + array('TIME' => $time, + 'NB_QUERIES' => $page['count_queries'], + 'SQL_TIME' => number_format($page['queries_time'],3,'.',' ').' s') + ); +} + +$template->assign('debug', $debug_vars ); + +trigger_action('loc_end_page_tail'); +// +// Generate the page +// +$template->parse('tail'); +$template->p(); +?>
\ No newline at end of file diff --git a/BSF/include/php_compat/array_intersect_key.php b/BSF/include/php_compat/array_intersect_key.php new file mode 100644 index 000000000..748b8f6f1 --- /dev/null +++ b/BSF/include/php_compat/array_intersect_key.php @@ -0,0 +1,35 @@ +<?php +// http://www.php.net/manual/en/function.array-intersect-key.php +// PHP 5 >= 5.1.0RC1 +function array_intersect_key() +{ + $args = func_get_args(); + if (count($args) < 2) { + trigger_error('Wrong parameter count for array_intersect_key()', E_USER_WARNING); + return; + } + + // Check arrays + $array_count = count($args); + for ($i = 0; $i !== $array_count; $i++) { + if (!is_array($args[$i])) { + trigger_error('array_intersect_key() Argument #' . ($i + 1) . ' is not an array', E_USER_WARNING); + return; + } + } + + // Compare entries + $result = array(); + foreach ($args[0] as $key1 => $value1) { + for ($i = 1; $i !== $array_count; $i++) { + foreach ($args[$i] as $key2 => $value2) { + if ((string) $key1 === (string) $key2) { + $result[$key1] = $value1; + } + } + } + } + + return $result; +} +?>
\ No newline at end of file diff --git a/BSF/include/php_compat/file_put_contents.php b/BSF/include/php_compat/file_put_contents.php new file mode 100644 index 000000000..679d9c984 --- /dev/null +++ b/BSF/include/php_compat/file_put_contents.php @@ -0,0 +1,14 @@ +<?php +//php 5 +function file_put_contents($filename, $data) +{ + $fp = fopen($filename, 'w'); + if ($fp) + { + $ret = fwrite($fp, $data); + fclose($fp); + return $ret; + } + return false; +} +?>
\ No newline at end of file diff --git a/BSF/include/php_compat/hash_hmac.php b/BSF/include/php_compat/hash_hmac.php new file mode 100644 index 000000000..5f05e370c --- /dev/null +++ b/BSF/include/php_compat/hash_hmac.php @@ -0,0 +1,25 @@ +<?php +//(hash) - enabled by default as of PHP 5.1.2 +function hash_hmac($algo, $data, $key, $raw_output=false) +{ + /* md5 and sha1 only */ + $algo=strtolower($algo); + $p=array('md5'=>'H32','sha1'=>'H40'); + if ( !isset($p[$algo]) or !function_exists($algo) ) + { + $algo = 'md5'; + } + if(strlen($key)>64) $key=pack($p[$algo],$algo($key)); + if(strlen($key)<64) $key=str_pad($key,64,chr(0)); + + $ipad=substr($key,0,64) ^ str_repeat(chr(0x36),64); + $opad=substr($key,0,64) ^ str_repeat(chr(0x5C),64); + + $ret = $algo($opad.pack($p[$algo],$algo($ipad.$data))); + if ($raw_output) + { + $ret = pack('H*', $ret); + } + return $ret; +} +?>
\ No newline at end of file diff --git a/BSF/include/php_compat/index.php b/BSF/include/php_compat/index.php new file mode 100644 index 000000000..c15b15795 --- /dev/null +++ b/BSF/include/php_compat/index.php @@ -0,0 +1,30 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// Recursive call +$url = '../'; +header( 'Request-URI: '.$url ); +header( 'Content-Location: '.$url ); +header( 'Location: '.$url ); +exit(); +?> diff --git a/BSF/include/php_compat/preg_last_error.php b/BSF/include/php_compat/preg_last_error.php new file mode 100644 index 000000000..c564aeba9 --- /dev/null +++ b/BSF/include/php_compat/preg_last_error.php @@ -0,0 +1,41 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// http://www.php.net/manual/fr/function.preg-last-error.php +// PHP 5 >= 5.2.0 +if (!defined('PREG_NO_ERROR')) + define('PREG_NO_ERROR', 0); +if (!defined('PREG_INTERNAL_ERROR')) + define('PREG_INTERNAL_ERROR', 1); +if (!defined('PREG_BACKTRACK_LIMIT_ERROR')) + define('PREG_BACKTRACK_LIMIT_ERROR', 2); +if (!defined('PREG_RECURSION_LIMIT_ERROR')) + define('PREG_RECURSION_LIMIT_ERROR', 3); +if (!defined('PREG_BAD_UTF8_ERROR')) + define('PREG_BAD_UTF8_ERROR', 4); + +function preg_last_error() +{ + return PREG_NO_ERROR; +} +?>
\ No newline at end of file diff --git a/BSF/include/picture_comment.inc.php b/BSF/include/picture_comment.inc.php new file mode 100644 index 000000000..ad0438d96 --- /dev/null +++ b/BSF/include/picture_comment.inc.php @@ -0,0 +1,183 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * This file is included by the picture page to manage user comments + * + */ + +// the picture is commentable if it belongs at least to one category which +// is commentable +$page['show_comments'] = false; +foreach ($related_categories as $category) +{ + if ($category['commentable'] == 'true') + { + $page['show_comments'] = true; + break; + } +} + +if ( $page['show_comments'] and isset( $_POST['content'] ) ) +{ + if ( is_a_guest() and !$conf['comments_forall'] ) + { + die ('Session expired'); + } + + $comm = array( + 'author' => trim( stripslashes(@$_POST['author']) ), + 'content' => trim( stripslashes($_POST['content']) ), + 'image_id' => $page['image_id'], + ); + + include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php'); + + $comment_action = insert_user_comment($comm, @$_POST['key'], $infos ); + + switch ($comment_action) + { + case 'moderate': + array_push( $infos, l10n('comment_to_validate') ); + case 'validate': + array_push( $infos, l10n('comment_added')); + break; + case 'reject': + set_status_header(403); + array_push($infos, l10n('comment_not_added') ); + break; + default: + trigger_error('Invalid comment action '.$comment_action, E_USER_WARNING); + } + + $template->assign( + ($comment_action=='reject') ? 'errors' : 'infos', + $infos + ); + + // allow plugins to notify what's going on + trigger_action( 'user_comment_insertion', + array_merge($comm, array('action'=>$comment_action) ) + ); +} +elseif ( isset($_POST['content']) ) +{ + set_status_header(403); + die('ugly spammer'); +} + +if ($page['show_comments']) +{ + // number of comment for this picture + $query = 'SELECT COUNT(*) AS nb_comments'; + $query.= ' FROM '.COMMENTS_TABLE.' WHERE image_id = '.$page['image_id']; + $query.= " AND validated = 'true'"; + $query.= ';'; + $row = mysql_fetch_array( pwg_query( $query ) ); + + // navigation bar creation + if (!isset($page['start'])) + { + $page['start'] = 0; + } + + $navigation_bar = create_navigation_bar( + duplicate_picture_url(array(), array('start')), + $row['nb_comments'], + $page['start'], + $conf['nb_comment_page'], + true // We want a clean URL + ); + + $template->assign( + array( + 'COMMENT_COUNT' => $row['nb_comments'], + 'COMMENT_NAV_BAR' => $navigation_bar, + ) + ); + + if ($row['nb_comments'] > 0) + { + $query = ' +SELECT id,author,date,image_id,content + FROM '.COMMENTS_TABLE.' + WHERE image_id = '.$page['image_id'].' + AND validated = \'true\' + ORDER BY date ASC + LIMIT '.$page['start'].', '.$conf['nb_comment_page'].' +;'; + $result = pwg_query( $query ); + + while ($row = mysql_fetch_array($result)) + { + $tpl_comment = + array( + 'AUTHOR' => trigger_event('render_comment_author', + empty($row['author']) + ? l10n('guest') + : $row['author']), + + 'DATE' => format_date( + $row['date'], + 'mysql_datetime', + true), + + 'CONTENT' => trigger_event('render_comment_content',$row['content']), + ); + + if (is_admin()) + { + $tpl_comment['U_DELETE'] = + add_url_params( + $url_self, + array( + 'action'=>'delete_comment', + 'comment_to_delete'=>$row['id'] + ) + ); + } + $template->append('comments', $tpl_comment); + } + } + + if (!is_a_guest() + or (is_a_guest() and $conf['comments_forall'])) + { + include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php'); + $key = get_comment_post_key($page['image_id']); + $content = ''; + if ('reject'===@$comment_action) + { + $content = htmlspecialchars($comm['content']); + } + $template->assign('comment_add', + array( + 'F_ACTION' => $url_self, + 'KEY' => $key, + 'CONTENT' => $content, + 'SHOW_AUTHOR' => !is_classic_user() + )); + } +} + +?>
\ No newline at end of file diff --git a/BSF/include/picture_metadata.inc.php b/BSF/include/picture_metadata.inc.php new file mode 100644 index 000000000..bc6410897 --- /dev/null +++ b/BSF/include/picture_metadata.inc.php @@ -0,0 +1,99 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * This file is included by the picture page to manage picture metadata + * + */ + +include_once(PHPWG_ROOT_PATH.'/include/functions_metadata.inc.php'); +if (($conf['show_exif']) and (function_exists('read_exif_data'))) +{ + if ($exif = @read_exif_data($picture['current']['image_path'])) + { + $exif = trigger_event('format_exif_data', $exif, $picture['current'] ); + + $tpl_meta = array( + 'TITLE' => 'EXIF Metadata', + 'lines' => array(), + ); + + foreach ($conf['show_exif_fields'] as $field) + { + if (strpos($field, ';') === false) + { + if (isset($exif[$field])) + { + $key = $field; + if (isset($lang['exif_field_'.$field])) + { + $key = $lang['exif_field_'.$field]; + } + $tpl_meta['lines'][$key] = $exif[$field]; + } + } + else + { + $tokens = explode(';', $field); + if (isset($exif[$tokens[0]][$tokens[1]])) + { + $key = $tokens[1]; + if (isset($lang['exif_field_'.$tokens[1]])) + { + $key = $lang['exif_field_'.$tokens[1]]; + } + $tpl_meta['lines'][$key] = $exif[$tokens[0]][$tokens[1]]; + } + } + } + $template->append('metadata', $tpl_meta); + } +} + +if ($conf['show_iptc']) +{ + $iptc = get_iptc_data($picture['current']['image_path'], + $conf['show_iptc_mapping']); + + if (count($iptc) > 0) + { + $tpl_meta = array( + 'TITLE' => 'IPTC Metadata', + 'lines' => array(), + ); + + foreach ($iptc as $field => $value) + { + $key = $field; + if (isset($lang[$field])) + { + $key = $lang[$field]; + } + $tpl_meta['lines'][$key] = $value; + } + $template->append('metadata', $tpl_meta); + } +} + + +?> diff --git a/BSF/include/picture_rate.inc.php b/BSF/include/picture_rate.inc.php new file mode 100644 index 000000000..aa1071452 --- /dev/null +++ b/BSF/include/picture_rate.inc.php @@ -0,0 +1,91 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * This file is included by the picture page to manage rates + * + */ + +if ($conf['rate']) +{ + if ( NULL != $picture['current']['average_rate'] ) + { + $query = ' +SELECT COUNT(rate) AS count + , ROUND(AVG(rate),2) AS average + , ROUND(STD(rate),2) AS std + FROM '.RATE_TABLE.' + WHERE element_id = '.$picture['current']['id'].' +;'; + $row = mysql_fetch_array(pwg_query($query)); + } + else + { // avg rate null -> no rate -> no need to query db + $row = array( 'count'=>0, 'average'=>NULL, 'std'=>NULL ); + } + $template->assign('rate_summary', $row); + + $user_rate = null; + if ($conf['rate_anonymous'] or is_autorize_status(ACCESS_CLASSIC) ) + { + if ($row['count']>0) + { + $query = 'SELECT rate + FROM '.RATE_TABLE.' + WHERE element_id = '.$page['image_id'] . ' + AND user_id = '.$user['id'] ; + + if ( !is_autorize_status(ACCESS_CLASSIC) ) + { + $ip_components = explode('.', $_SERVER['REMOTE_ADDR']); + if ( count($ip_components)>3 ) + { + array_pop($ip_components); + } + $anonymous_id = implode ('.', $ip_components); + $query .= ' AND anonymous_id = \''.$anonymous_id . '\''; + } + + $result = pwg_query($query); + if (mysql_num_rows($result) > 0) + { + $row = mysql_fetch_array($result); + $user_rate = $row['rate']; + } + } + + $template->assign( + 'rating', + array( + 'F_ACTION' => add_url_params( + $url_self, + array('action'=>'rate') + ), + 'USER_RATE'=> $user_rate, + 'marks' => $conf['rate_items'] + ) + ); + } +} + +?>
\ No newline at end of file diff --git a/BSF/include/section_init.inc.php b/BSF/include/section_init.inc.php new file mode 100644 index 000000000..ffd6cac1a --- /dev/null +++ b/BSF/include/section_init.inc.php @@ -0,0 +1,620 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/** + * This included page checks section related parameter and provides + * following informations: + * + * - $page['title'] + * + * - $page['items']: ordered list of items to display + * + */ + +// "index.php?/category/12-foo/start-24" or +// "index.php/category/12-foo/start-24" +// must return : +// +// array( +// 'section' => 'categories', +// 'category' => array('id'=>12, ...), +// 'start' => 24 +// ); + +$page['items'] = array(); + +// some ISPs set PATH_INFO to empty string or to SCRIPT_FILENAME while in the +// default apache implementation it is not set +if ( $conf['question_mark_in_urls']==false and + isset($_SERVER["PATH_INFO"]) and !empty($_SERVER["PATH_INFO"]) ) +{ + $rewritten = $_SERVER["PATH_INFO"]; + $rewritten = str_replace('//', '/', $rewritten); + $path_count = count( explode('/', $rewritten) ); + $page['root_path'] = PHPWG_ROOT_PATH.str_repeat('../', $path_count-1); +} +else +{ + $rewritten = ''; + foreach (array_keys($_GET) as $keynum => $key) + { + $rewritten = $key; + break; + } + $page['root_path'] = PHPWG_ROOT_PATH; +} + +// deleting first "/" if displayed +$tokens = explode( + '/', + preg_replace('#^/#', '', $rewritten) + ); +// $tokens = array( +// 0 => category, +// 1 => 12-foo, +// 2 => start-24 +// ); + +$next_token = 0; +if (script_basename() == 'picture') // basename without file extention +{ // the first token must be the identifier for the picture + if ( isset($_GET['image_id']) + and isset($_GET['cat']) and is_numeric($_GET['cat']) ) + {// url compatibility with versions below 1.6 + $url = make_picture_url( array( + 'section' => 'categories', + 'category' => get_cat_info($_GET['cat']), + 'image_id' => $_GET['image_id'] + ) ); + redirect($url); + } + $token = $tokens[$next_token]; + $next_token++; + if ( is_numeric($token) ) + { + $page['image_id'] = $token; + } + else + { + preg_match('/^(\d+-)?(.*)?$/', $token, $matches); + if (isset($matches[1]) and is_numeric($matches[1]=rtrim($matches[1],'-')) ) + { + $page['image_id'] = $matches[1]; + if ( !empty($matches[2]) ) + { + $page['image_file'] = $matches[2]; + } + } + else + { + if ( !empty($matches[2]) ) + { + $page['image_file'] = $matches[2]; + } + else + { + bad_request('picture identifier is missing'); + } + } + } +} + +$page = array_merge( $page, parse_section_url( $tokens, $next_token) ); +if ( !isset($page['section']) ) +{ + $page['section'] = 'categories'; + + switch (script_basename()) + { + case 'picture': + break; + case 'index': + { + // No section defined, go to selected url + if (!empty($conf['random_index_redirect']) and empty($tokens[$next_token]) ) + { + $random_index_redirect = array(); + foreach ($conf['random_index_redirect'] as $random_url => $random_url_condition) + { + if (empty($random_url_condition) or eval($random_url_condition)) + { + $random_index_redirect[] = $random_url; + } + } + if (!empty($random_index_redirect)) + { + redirect($random_index_redirect[mt_rand(0, count($random_index_redirect)-1)]); + } + } + break; + } + default: + trigger_error('script_basename "'.script_basename().'" unknown', + E_USER_WARNING); + } +} + + +$page = array_merge( $page, parse_well_known_params_url( $tokens, $next_token) ); + + +if ( script_basename()=='picture' and 'categories'==$page['section'] and + !isset($page['category']) and !isset($page['chronology_field']) ) +{ //access a picture only by id, file or id-file without given section + $page['flat']=true; +} + +// $page['nb_image_page'] is the number of picture to display on this page +// By default, it is the same as the $user['nb_image_page'] +$page['nb_image_page'] = $user['nb_image_page']; + +if (pwg_get_session_var('image_order',0) > 0) +{ + $orders = get_category_preferred_image_orders(); + + $conf['order_by'] = str_replace( + 'ORDER BY ', + 'ORDER BY '.$orders[ pwg_get_session_var('image_order',0) ][1].',', + $conf['order_by'] + ); + $page['super_order_by'] = true; +} + +$forbidden = get_sql_condition_FandF( + array + ( + 'forbidden_categories' => 'category_id', + 'visible_categories' => 'category_id', + 'visible_images' => 'id' + ), + 'AND' + ); + +// +-----------------------------------------------------------------------+ +// | category | +// +-----------------------------------------------------------------------+ +if ('categories' == $page['section']) +{ + if (isset($page['category'])) + { + $page = array_merge( + $page, + array( + 'comment' => + trigger_event( + 'render_category_description', + $page['category']['comment'], + 'main_page_category_description' + ), + 'title' => + get_cat_display_name($page['category']['upper_names'], '', false), + ) + ); + } + else + { + $page['title'] = l10n('no_category'); + } + + if + ( + (!isset($page['chronology_field'])) and + ( + (isset($page['category'])) or + (isset($page['flat'])) + ) + ) + { + if ( !empty($page['category']['image_order']) and !isset($page['super_order_by']) ) + { + $conf[ 'order_by' ] = ' ORDER BY '.$page['category']['image_order']; + } + + if (isset($page['flat'])) + {// flat categories mode + if ( isset($page['category']) ) + { // get all allowed sub-categories + $query = ' +SELECT id + FROM '.CATEGORIES_TABLE.' + WHERE + uppercats LIKE "'.$page['category']['uppercats'].',%" ' + .get_sql_condition_FandF( + array + ( + 'forbidden_categories' => 'id', + 'visible_categories' => 'id', + ), + "\n AND" + ); + $subcat_ids = array_from_query($query, 'id'); + $subcat_ids[] = $page['category']['id']; + $where_sql = 'category_id IN ('.implode(',',$subcat_ids).')'; + // remove categories from forbidden because just checked above + $forbidden = get_sql_condition_FandF( + array( 'visible_images' => 'id' ), + 'AND' + ); + } + else + { + $where_sql = '1=1'; + } + } + else + {// Normal mode + $where_sql = 'category_id = '.$page['category']['id']; + } + + // Main query + $query = ' +SELECT DISTINCT(image_id) + FROM '.IMAGE_CATEGORY_TABLE.' + INNER JOIN '.IMAGES_TABLE.' ON id = image_id + WHERE + '.$where_sql.' +'.$forbidden.' + '.$conf['order_by'].' +;'; + + $page['items'] = array_from_query($query, 'image_id'); + } //otherwise the calendar will requery all subitems +} +// special sections +else +{ +// +-----------------------------------------------------------------------+ +// | tags section | +// +-----------------------------------------------------------------------+ + if ($page['section'] == 'tags') + { + $page['tag_ids'] = array(); + foreach ($page['tags'] as $tag) + { + array_push($page['tag_ids'], $tag['id']); + } + + $items = get_image_ids_for_tags($page['tag_ids']); + + // permissions depends on category, so to only keep images that are + // reachable to the connected user, we need to check category + // associations + if (!empty($items) ) + { + $query = ' +SELECT DISTINCT image_id + FROM '.IMAGE_CATEGORY_TABLE.' INNER JOIN '.IMAGES_TABLE.' ON image_id=id + WHERE image_id IN ('.implode(',', $items).') + '.$forbidden. + $conf['order_by'].' +;'; + $items = array_from_query($query, 'image_id'); + } + + $title = get_tags_content_title(); + + $page = array_merge( + $page, + array( + 'title' => $title, + 'items' => $items, + ) + ); + } +// +-----------------------------------------------------------------------+ +// | search section | +// +-----------------------------------------------------------------------+ + if ($page['section'] == 'search') + { + include_once( PHPWG_ROOT_PATH .'include/functions_search.inc.php' ); + + $search_result = get_search_results($page['search']); + if ( !empty($search_result['items']) and !isset($search_result['as_is']) ) + { + $query = ' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE id IN ('.implode(',', $search_result['items']).') + '.$forbidden.' + '.$conf['order_by'].' +;'; + $page['items'] = array_from_query($query, 'id'); + } + else + { + $page['items'] = $search_result['items']; + if ( isset($search_result['qs']) ) + {//save the details of the query search + $page['qsearch_details'] = $search_result['qs']; + } + } + + $page = array_merge( + $page, + array( + 'title' => '<a href="'.duplicate_index_url(array('start'=>0)).'">' + .l10n('search_result').'</a>', + ) + ); + } +// +-----------------------------------------------------------------------+ +// | favorite section | +// +-----------------------------------------------------------------------+ + else if ($page['section'] == 'favorites') + { + check_user_favorites(); + + $query = ' +SELECT image_id + FROM '.FAVORITES_TABLE.' + INNER JOIN '.IMAGES_TABLE.' ON image_id = id + WHERE user_id = '.$user['id'].' +'.get_sql_condition_FandF + ( + array + ( + 'visible_images' => 'image_id' + ), + 'AND' + ).' + '.$conf['order_by'].' +;'; + + $page = array_merge( + $page, + array( + 'title' => l10n('favorites'), + 'items' => array_from_query($query, 'image_id'), + ) + ); + } +// +-----------------------------------------------------------------------+ +// | recent pictures section | +// +-----------------------------------------------------------------------+ + else if ($page['section'] == 'recent_pics') + { + $query = ' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE + date_available >= SUBDATE( + CURRENT_DATE,INTERVAL '.$user['recent_period'].' DAY) + '.$forbidden.' + '.$conf['order_by'].' +;'; + + $page = array_merge( + $page, + array( + 'title' => '<a href="'.duplicate_index_url(array('start'=>0)).'">' + .l10n('recent_pics_cat').'</a>', + 'items' => array_from_query($query, 'id'), + ) + ); + } +// +-----------------------------------------------------------------------+ +// | recently updated categories section | +// +-----------------------------------------------------------------------+ + else if ($page['section'] == 'recent_cats') + { + $page = array_merge( + $page, + array( + 'title' => l10n('recent_cats_cat'), + ) + ); + } +// +-----------------------------------------------------------------------+ +// | most visited section | +// +-----------------------------------------------------------------------+ + else if ($page['section'] == 'most_visited') + { + $page['super_order_by'] = true; + $conf['order_by'] = ' ORDER BY hit DESC, file ASC'; + $query = ' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE hit > 0 + '.$forbidden.' + '.$conf['order_by'].' + LIMIT 0, '.$conf['top_number'].' +;'; + + $page = array_merge( + $page, + array( + 'title' => '<a href="'.duplicate_index_url(array('start'=>0)).'">' + .$conf['top_number'].' '.l10n('most_visited_cat').'</a>', + 'items' => array_from_query($query, 'id'), + ) + ); + } +// +-----------------------------------------------------------------------+ +// | best rated section | +// +-----------------------------------------------------------------------+ + else if ($page['section'] == 'best_rated') + { + $page['super_order_by'] = true; + $conf['order_by'] = ' ORDER BY average_rate DESC, id ASC'; + + $query =' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE average_rate IS NOT NULL + '.$forbidden.' + '.$conf['order_by'].' + LIMIT 0, '.$conf['top_number'].' +;'; + $page = array_merge( + $page, + array( + 'title' => '<a href="'.duplicate_index_url(array('start'=>0)).'">' + .$conf['top_number'].' '.l10n('best_rated_cat').'</a>', + 'items' => array_from_query($query, 'id'), + ) + ); + } +// +-----------------------------------------------------------------------+ +// | list section | +// +-----------------------------------------------------------------------+ + else if ($page['section'] == 'list') + { + $query =' +SELECT DISTINCT(id) + FROM '.IMAGES_TABLE.' + INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON id = ic.image_id + WHERE image_id IN ('.implode(',', $page['list']).') + '.$forbidden.' + '.$conf['order_by'].' +;'; + + $page = array_merge( + $page, + array( + 'title' => '<a href="'.duplicate_index_url(array('start'=>0)).'">' + .l10n('random_cat').'</a>', + 'items' => array_from_query($query, 'id'), + ) + ); + } +} + +// +-----------------------------------------------------------------------+ +// | chronology | +// +-----------------------------------------------------------------------+ + +if (isset($page['chronology_field'])) +{ + include_once( PHPWG_ROOT_PATH.'include/functions_calendar.inc.php' ); + initialize_calendar(); +} + +if (script_basename() == 'picture' + and !isset($page['image_id']) ) +{ + if ( !empty($page['items']) ) + { + $query = ' +SELECT id,file + FROM '.IMAGES_TABLE .' + WHERE file LIKE "' . $page['image_file'] . '.%" ESCAPE "|"'; + if ( count($page['items']) < 500) + {// for very large item sets do not add IN - because slow + $query .= ' + AND id IN ('.implode(',',$page['items']).') + LIMIT 0,1'; + } + $result = pwg_query($query); + switch (mysql_num_rows($result)) + { + case 0: break; + case 1: + list($page['image_id'], $page['image_file']) = mysql_fetch_row($result); + break; + default: // more than 1 file name match + while ($row = mysql_fetch_row($result) ) + { + if ( in_array($row[0], $page['items']) ) + { + list($page['image_id'], $page['image_file']) = $row; + break; + } + } + } + } + if ( !isset($page['image_id']) ) + { + $page['image_id'] = -1; // will fail in picture.php + } +} + +// add meta robots noindex, nofollow to avoid unnecesary robot crawls +$page['meta_robots']=array(); +if ( isset($page['chronology_field']) + or ( isset($page['flat']) and isset($page['category']) ) + or 'list'==$page['section'] or 'recent_pics'==$page['section'] ) +{ + $page['meta_robots']=array('noindex'=>1, 'nofollow'=>1); +} +elseif ('tags' == $page['section']) +{ + if ( count($page['tag_ids'])>1 ) + { + $page['meta_robots']=array('noindex'=>1, 'nofollow'=>1); + } +} +elseif ('recent_cats'==$page['section']) +{ + $page['meta_robots']['noindex']=1; +} +elseif ('search'==$page['section']) +{ + $page['meta_robots']['nofollow']=1; +} +if ( $filter['enabled'] ) +{ + $page['meta_robots']['noindex']=1; +} + +// see if we need a redirect because of a permalink +if ( 'categories'==$page['section'] and isset($page['category']) ) +{ + $need_redirect=false; + if ( empty($page['category']['permalink']) ) + { + if ( $conf['category_url_style'] == 'id-name' and + @$page['hit_by']['cat_url_name'] !== str2url($page['category']['name']) ) + { + $need_redirect=true; + } + } + else + { + if ( $page['category']['permalink'] !== @$page['hit_by']['cat_permalink'] ) + { + $need_redirect=true; + } + } + + if ($need_redirect) + { + $redirect_url = ( script_basename()=='picture' + ? duplicate_picture_url() + : duplicate_index_url() + ); + if (!headers_sent()) + { // this is a permanent redirection + set_status_header(301); + redirect_http( $redirect_url ); + } + redirect( $redirect_url ); + } + unset( $need_redirect, $page['hit_by'] ); +} + +trigger_action('loc_end_section_init'); +?>
\ No newline at end of file diff --git a/BSF/include/smarty/COPYING.lib b/BSF/include/smarty/COPYING.lib new file mode 100644 index 000000000..3b204400c --- /dev/null +++ b/BSF/include/smarty/COPYING.lib @@ -0,0 +1,458 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/BSF/include/smarty/NEWS b/BSF/include/smarty/NEWS new file mode 100644 index 000000000..fa550ff18 --- /dev/null +++ b/BSF/include/smarty/NEWS @@ -0,0 +1,1024 @@ +Version 2.6.19 (Feb 11th, 2008) +------------------------------- + +- fix regex_replace allowing \0 in the search string (c960657, + monte) +- add append feature to {capture} (jablko, monte) +- fix when (un)registering filters with the same method name but different class + name (danilo) +- fix calling registered objects' methods with an empty argument list + (marcello, messju) + +Version 2.6.18 (Mar 7th, 2007) +------------------------------ + +- fix html_select_date separator when parts are missing (hayk, + monte) +- fix broken detection of non-cached blocks introduced in 2.6.17 + (messju) + +Version 2.6.17 (Mar 5th, 2007) +------------------------------ + +- fix php handling (monte, boots, danilo) +- fix handling of plugin tags directly followed by an else tag (Fahr, danilo) +- fix handling of $etc in the truncate modifier when $etc is longer + than $length (Sylvinus, messju) +- fix handling of %I with mysql timestamps in the date_format modifier + (danilo, boots) +- update smarty_core_write_file() and smarty_modifier_date_format() to better + recognize Windows (boots, danilo) +- emulate %h, %n, %r, %R, %t in the date_format modifier on Windows + (danilo, boots) + +Version 2.6.16 (Dec 1st, 2006) +------------------------------ + +- fixed replacement bug in trimwhitespace output filter that was introduced + in the last release (Spuerhund, boots) + +Version 2.6.15 (Nov 30th, 2006) +------------------------------- + +- change file writing semantics in smarty_core_write_file() to unlink() only + when rename() fails or a Windows system is detected (c960657, boots) +- update debug.tpl to xhtml 1.1 compliance, fix javascript escaping in debug + output and apply a Smarty based color scheme (cybot, boots) +- enhance reporting precision of debug_print_var modifier (cybot, boots) +- make html_select_date work consistently with 0000-00-00 00:00:00 and + 0000-00-00 inputs (cybot, boots) +- fix wrong handling of insert's name attribute. (messju) +- fix false replacement of "$t" inside double quotes (checat, messju) +- added support for column headings and caption element to html_table and + updated the output to use thead/tbody elements (boots) +- fixed ordering of replacements in trimwhitespace output filter (Getty, boots) +- update mailto function plugin to work around a firefox/thunderbird + escaping bug (elijahlofgren, boots) +- emulate %l in the date_format modifier on windows (boots) +- fix handling of apostrophes in capitalize modifier (Alec Smecher, boots) + +Version 2.6.14 (May 28th, 2006) +------------------------------- + +- fix compiler bug allowing php tags in secure templates + (boots,monte) +- un-hide hidden xml open tags (boots) +- fix handling of block-methods of registered objects (El Hombre Gris, + messju) + +Version 2.6.13 (March 9th, 2006) +-------------------------------- + + - update regex_replace, removing possible use of "e" modifier + +Version 2.6.12 (Jan 18th, 2006) +------------------------------- + + - fix improper use of references in the compiler handling cached + attributes and in compiled code handling block plugins (messju) + - make Smarty::_read_file() work on latest php (messju) + - fixed improper tokenization of certain inline math expressions (boots) + +Version 2.6.11 (Dec 14, 2005) +----------------------------- + + - fixed code generation of non-cacheable blocks to play well with php's + "Alternative syntax for control structures" (kihara, messju) + - fix handling of multiple identical inserts in one display()-call (messju) + - replace {} string access with equivalent substr() to avoid E_STRICT + warnings in PHP 5.1 (boots) + - return valid reference in get_config_vars() when given var is + non-existant (Thomas Schulz, boots) + - plugin html_image: fix incorrect secure_dir error when + file doesn't exist (monte) + - plugin html_image: add path_prefix param (monte) + - add char_set parameter to escape modifier (Loading, monte) + - fix notice in debug security check (Drakla, monte) + - return valid reference in get_template_vars() when given var is + non-existant (monte) + - add escape type "urlpathinfo" to escape modifier (monte) + +Version 2.6.10 (Aug 5, 2005) +---------------------------- + + - allow secure_dir to be a filename, not just + a directory name (monte) + - set debug.tpl as a secure_dir, not the entire + SMARTY_DIR (monte) + - fix proper escaping for literal strings in + Smarty_Compiler::_parse_var_props() (boots, messju) + - remove ambiguity for numeric values passed to smarty_make_timestamp() + (and thus the date_format modifier). numeric values are treated as + timestamps now. (andreas, messju) + - add passthru attribute feature to html_select_date (Sedgar, + monte) + - add "middle" parameter to truncate (monte) + - make form input label ids optional (monte) + - add error message for empty if/elseif statements (eykanal, + monte) + - cast selected value to string for comparison in html_radios + (Exeption, monte) + - updated html_select_date's year_as_text-feature to be xhtml compliant + (Mark West, messju) + - fix handling of selected month html_select_date (Yuri Weseman, messju) + +Version 2.6.9 (Mar 31, 2005) +---------------------------- + + - disallow variable function calls in {if} statements (messju, monte) + - disallow variable function calls in {math} equations (messju, monte) + +Version 2.6.8 (Mar 21, 2005) +---------------------------- + + - remove e-modifier from regex_replace modifier (messju) + - remove cast of object to array in foreach's from-attribute (messju) + - add "null" as a valid token for {if} when security is enabled (messju) + - add javascript_charcode encoding option to mailto function + (monte) + - add ids to html_radios labels (monte, menulis) + - fix handling of strip-tags with non-default delimiters (Mark West, messju) + +Version 2.6.7 (Feb 3, 2005) +--------------------------- + + - fix handling of hashed opening php-tags inside strip-blocks (messju) + - removed border tag from html_image function (monte) + - change escape:url use rawurlencode() instead of urlencode() (messju) + - make $smarty.const.FOO compile to "FOO", and not to "constant('foo')". + this is less code and a little faster execution. note that undefined + constants are now displayed as the constant's name. (messju) + - make block functions and registered objects' block methods use a + local variable for block_content instead of a property of $smarty (messju) + - fix escaping in the generated code that calls smarty_core_load_plugins + (jes5199, messju) + - fix invalid HTML issue with popup (Stefanos Harhalakis, + Monte) + - fixed {popup} to properly handle inarray and function parameters and added + support for mouseoff and followmouse options (boots) + +Version 2.6.6 (Oct 13, 2004) +---------------------------- + + - fixed nocache-handling with nested includes (Lars Jankowfsky, messju) + - moved /libs/core to /libs/internals (boots) + - fixed more parsing problems (messju) + +Version 2.6.5 (Sept 13, 2004) +----------------------------- + + - fixed some parsing problems with object calls introduced + in 2.6.4 (Monte) + - add $smarty->security_settings['ALLOW_CONSTANTS']. note: this + defaults to false which means you have to allow them explicitly + in your secured templates from now on! (messju) + +Version 2.6.4 (Sept 7, 2004) +---------------------------- + + - add $smarty.ldelim and $smarty.rdelim to smarty special var (Monte) + - fall back to old uniqid()-behaviour when tempnam() fails in + core.write_file.php (messju) + - fix capitalize modifier, don't rely on buggy ucwords (Monte) + - make html_select_date work with negative timestamps, also + force year range to include given date unless explicitly + set (Garo, Monte) + - fix bug with {fetch}, passing user/pass in url did not work + (Monte) + - fix occasional wrong error messages on mismatched tags when + {else}, {elseif}, {foreachelse} or {sectionelse} is involved (messju) + - fix handling of methods arguments (messju, Manfred Wischin) + - remove touch() call that made the compiled-template's timestamp the + same as the source-template's one. (messju) + - add assign attribute to html_checkboxes and html_radios + (pcg, Monte) + - remove non-xhtml conformant tag from mailto function + (tacker, Monte) + - handle date_format codes %e, %T and %D for windows (tip, + Monte) + - fix unnecessary call to smarty_core_get_include_path() inside + Smarty::_get_auto_filename() (c960657, messju) + - add error-messages when anything else than an identifier is passed + to foreach's key- or item-attribute (messju) + - fix handling of digits inside tagnames (messju) + - fix escaping of backslashes in Smarty_Compiler::_quote_replace() (messju) + +Version 2.6.3 (June 16, 2004) +----------------------------- + + - added escapement of '</' to '<\/' in escape:javascript + modifier (c960657, Monte) + - added obfuscation of protocol-string in {mailto} when using hex- + encoding (bharat, messju) + - enhanced auto-generated filenames for templates_c and cache (messju) + - add 'nonstd' to escape modifier for escaping non-std chars, + such as ms doc quote (Monte) + - adjusted textformat to not output wrap chars after last para + (Monte) + - use tempnam() instead of unqid() to create better temporary files in + smarty_core_write_file() (xces, messju) + - add 'mail' to escape modifier for safe display of e-mail + addresses (Monte) + - add cycle function attribute "reset" to english docs (Monte) + - enhanced support of numeric constants as variable-expressions (messju) + - add case decentity to smarty_modifier_escape() (Konstantin A. Pelepelin, + messju) + - make smarty_core_write_compiled_include() php5-aware (messju) + - removed unused functionality to load a subset of lines from a file (messju) + - fix is_secure() should only check if a file is_readable, not if + the directory where it is in is readable (sagi, messju) + - fix problem displaying debug console when $default_resource_type + is not "file:" (c960657, Monte) + - fix permission handling with security and config_load (messju) + - removed '.' from the list of default template locations in + _parse_resource_name() (messju) + - fix avoid warning with template_exists() on an absolute paths (messju) + - fix parameters passed to resource's secure()-function (messju) + - fix handling of integer values like width and delay im + smarty_function_popup() (messju) + +Version 2.6.2 (Feb 17, 2004) +---------------------------- + + - fix allow empty years, months and days in html_select_date's + time-attribute (messju) + - fix YES and NO should not be booleanized inside triple-quotes in a + config-file (messju) + - fix accidently slurped line following a triple-quoted value in a + config-file (messju) + - change default for use_sub_dirs to false (messju) + - fix quoting of values in smarty_function_popup() (messju) + - fix handling of hidden sections in Config_File (messju) + - add handling of resources for {config_load} (messju) + - fix bug when using arrays with tr_attr and td_attr in {html_table} (messju) + - add unit testing to cvs core (Monte) + +Version 2.6.1 (Jan 16, 2004) +---------------------------- + + - rename $smarty->tpl_error_reporting to $smarty->error_reporting + (messju) + - fix interpretation of $smarty->security in {html_image} (messju) + - add caching of requested paths to _assemble_plugin_filepath() (messju) + - fix handling of comments inside {php}- and {literal}-blocks (messju) + - fix bug handling triple-quotes in config-files (BRDude, messju) + - change default of request_use_auto_globals to true - $_SERVER is + now preferred over $HTTP_SERVER_VARS (messju) + - re-add support for $SCRIPT_NAME (messju) + - reactivate $smarty->default_modifiers (messju) + - add cookie persistance to debug console (Monte) + - allow single-digit days and months without smarty_make_timestamp() + in html_select_date (messju) + - fix headers sent erroneously with cache_modified_check and fetch() + (wphilips, messju) + - fix config_file path bug (Marc Cabadas, Monte) + - fix 'is even by' and 'is odd by' logic (Monte) + - add day_empty, month_empty, year_empty and all_empty attributes to + html_select_date (messju) + - add table of explanation for {if} qualifiers in docs (boots) + - fix bug when comparing array-keys to "selected" in html_options + and html_checkboxes (messju) + - add better checks for correctly nested tags when compiling (messju) + - remove {$SCRIPT_NAME}. use {$smarty.server.SCRIPT_NAME} instead (messju) + - remove $global_assign. assign global variables explicitly instead (messju) + - fix example for count_characters in docs (boots) + - add section new basic syntax section "Escaping Smarty Parsing" in docs (boots) + - fix error handler call in config_load (boots) + - remove warning in debug_print_var on php-resources (messju) + - move function.assign.php to compiler.assign.php (messju) + - add property $tpl_error_reporting (messju) + - remove property $undefined. "null" is used literally instead (messju) + +Version 2.6.0 (Nov 19, 2003) +---------------------------- + + - move Smarty::quote_replace() to Smarty_Compiler::_quote_replace() (messju) + - remove import of of attributes of {include_php} to php's namespace. + use $params[name] instead (messju) + +Version 2.6.0-RC3 (Nov 13, 2003) +-------------------------------- + + - fix handling of $var.key inside [] (messju) + - fix handling of assign inside {insert}-tags (messju) + - fix handling if [...] inside triple-quotes in config-files (messju) + - fix handling of simple-math-operators inside modifiers (Dominik, messju) + - fix handling of trailing-slashes in open_basedir in + smarty_core_create_dir_structure() (packman, messju) + +Version 2.6.0-RC2 (Oct 8, 2003) +------------------------------- + + - apply modifiers only once to section-loop and foreach-from attrs (messju) + - remove use of _smarty_cached_paths-files (messju) + - remove Smarty::_plugin_implementation_exists() - use is_callable() (messju) + - ignore {strip}/{/strip) inside {strip}-blocks (messju) + - fixed removal of leading/trailing newlines in {strip}-blocks (messju) + - fixed proper escaping of " and ' with escape:javascript (messju) + - fixed bug in traversal of $smarty->plugins_dir-array. now the + first matching plugin is taken (messju) + - moved {strip} back into the compiler (messju) + - fixed config_load: handling of section-attribute and use of + multiple config-files in one template (atu, messju) + +Version 2.6.0-RC1 (August 11, 2003) +----------------------------------- + + - fixed status-header for cache_modified_check under cgi-sapi (messju) + - added optional parameter $cache_attrs to register_function() and + register_block(). $cache_attrs is an array containing attribute- + names that should be cached on calls to functions that have + $cacheable set to false. (messju) + - enabled registration of class-methods as callbacks for the register_*- + functions (use: array('classname', 'method_name')) as callback) (messju) + - added filepath caching (Monte) + - added optional assign-attribute to {capture}-tag (messju) + - added $cacheable-parameter to register_compiler_function() (messju) + - added $cacheable-parameter with default=true to register_function() + and register_block() (messju) + - add math speedup to core (Dominik, Monte) + - fix newlines for tags without template output (Monte) + - added config-option "request_use_auto_globals" to make auto-globals be + used as request vars instead of HTTP_*_VARS (messju) + - speed up config_load, simplify compiling (Monte) + - added block-methods for registered objects (Bharat Mediratta, messju) + - ignore one char resource names like c:foo.tpl (Monte) + - added default_resource_type feature (Monte) + - fix bug where config file starts with hidden section (boots, Monte) + - add discrete error checking pertaining to $cache_dir + and $compile_dir, their existance and writability (Monte) + - fixed behaviour of start=... for {counter} (messju) + - fixed assign for {counter} (messju) + - added params vdir, hdir and inner to html_table to allow looping + over the data in various directions (messju) + - allow spaces in literal tags (Paul Lockaby, Monte) + - speed up compiled templates, hardcode plugin filepaths + instead of dynamically calculate at runtime. (Monte) + - abstract many core components from Smarty.class.php, + speeding up core class instantiation (Monte) + - fixed bug in _create_dir_structure() when used with open_basedir- + restriction and relative paths (messju) + - use DIRECTORY_SEPARATOR exclusively, keep DIR_SEP for BC (Monte) + - changed "link" to "href" in html_image. "link" is still working + but deprecated (messju) + - html_image always renders an alt-tag now (default alt="") (messju) + - fixed assign attribute for multiple counters (messju) + - added simple math operators to variables (Monte) + - enabled array(&$obj. 'source', 'timestamp', 'secure', 'trusted') + as callback for register_resource() (messju); + - enabled array(&$obj, 'method') as callback for + $default_template_handler_func (messju) + - remove unnecessary close/open tags from compiled templates + (Monte) + - fixed errornous creation of '//' in image_path in html_image (messju) + - fix escapement of special chars for key vals in debug + console (Monte) + - fixed debug timing logic for config_load (Tom Sommer, Monte) + - all in-code doc comments converted to phpDocumentor format (Greg) + - moved strip from smarty core to plugin (Monte) + - moved config_load from smarty core to plugin (Monte) + - added &$repeat-parameter to block-functions (messju) + - enabled hex-constants in function.math.php (messju) + - enabled hex-constants (0x...) as function-attributes, inside if-statements + and as modifier-parameters (messju) + - fixed bug with passing $smarty as reference in Smarty.compiler.class + (messju) + - corrected output with {strip} and PHP tag newlines (Monte) + - added possibility to register function-callbacks as "array(&$obj, 'method)" + this affects register_function(), -block, -compiler_function, -modifier, + -prefilter, -postfilter, -outputfilter-functions() and $cache_handler_func + (messju) + - added <labels> to html_checkboxes and html_radios (Philippe, messju) + - added "labels"-options to turn off labels in html_checkboxes and _radios + (messju) + +Version 2.5.0 (April 11, 2003) +------------------------------ + + - fixed bug with default modifier when passing integer 0 + (Monte) + - change backtic syntax from $`foo` to `$foo` (Monte) + - recognize $foo[][] syntax inside embedded quotes without + backtics (Monte) + - name=123 is passed as an integer (not a string) to plugins now (messju) + - $length is now propagated to sub-values in debug_print_var (messju) + +Version 2.5.0-RC2 (March 26, 2003) +---------------------------------- + + - made clear_cache() ignore compile_id, when clearing cache-groups (this + is when no $tpl_file is supplied) (messju) + - made onmouseout XHTML-compliant in function.popup.php (messju) + - applied local-var-naming-scheme to fetch() (messju) + - renamed $localvars to $_localvars in cache-file-handling-functions, + added _get_auto_id()-function (messju) + - swapped compile_id and cache_id in read_cache_file and write_cache_file + (messju) + - reverted patch for cache-file-handling (messju) + - made html_radios and html_checkboxes accept "selected" instead + of "checked" optionally. (messju) + - made compile_id ignored in clear_cache, made order of + auto_file_name $cache_id.$compile_id again, applied the the new + variable-naming-scheme for cache_file_handing functions (messju) + - removed notice of undefined var in _rm_auto() (messju) + - added warning message when an array is passed as + the "checked" value of html_radios (Monte) + - fixed errormessage in _compile_smarty_ref() (messju) + - updated docs for html_image "name" -> "file" (messju) + - fixed bug with html_options-optgroups (Nichlas Löfdahl, messju) + - cleaned up calls to readdir() (messju) + - fixed bug with passing multiple modifiers to a parameter + (Monte) + - updated docs for html_checkboxes, html_options and html_radios (messju) + - fixed wrong default "name" attribute for html_options (messju) + - html_checkboxes now expect the options as attribute "options" instead + of "checkboxes. html_radios expect "options" instead of "radios". + cleaned up indentiation (messju) + - fixed too greedy str_replace in trimwhitespace outputfilter (messju) + - html_checkboxes and html_radios passthru all unknown paramters now + additionally their output is now XHTML compliant (messju) + - html_options passthru all unknown paramters now (messju) + - fix link functionality of html_image, also make + output XHTML compatible (Hinrich Donner, Monte) + - append "@" to default modifier vars/args + supress possible warnings (Monte) + - fix problem with escaped double quotes (Monte) + - fix html_radios to not return an array (Monte) + - fixed length in modifier.truncate.php (messju) + - fixed handling of '$'-signs in trimwhitespace outputfilter (messju) + - fix bug that makes config files recompile every time + (Nagger, Monte) + - add dpi functionality to html_image, change "name" + parameter to "file" (Thomas Shulz, Monte) + - fix height/width parameter index in html_image (Gerard, + Monte) + - get rid of unsetting name and script attributes + to insert tag (Thomas Schulz, Monte) + - changed argument order of string_format modifier back, + was right in the first place (Monte) + +Version 2.5.0-RC1 (March 5, 2003) +--------------------------------- + + - fixed notice in popup function (Nagger, Monte) + - fix "once" var compiling for include_php (Monte) + - added nl2br modifier to distribution (Monte) + - added html_image to distribution (Monte) + - added cat modifier to distribution (Monte) + - added html_table to distribution (Monte) + - added << >> <> support to if statments (SMK, Monte) + - fix _assign_smarty_interface to not overwrite keys + other than 'request' (Jerome Poudevigne, Monte) + - added html_checkboxes to distribution (Christopher Kvarme, Monte) + - added html_radios to distribution (Christopher Kvarme, Monte) + - fixed string_format modifier args (wrong order) (Paul + Lockaby, Monte) + - use tmp file for file writes, avoid file lock race (Monte) + - support syntax "$`smarty.config.foo`.tpl" for embedded + vars in quotes, and allow full dollar var syntax (Monte) + - add $smarty.config.varname variable for accessing config vars (Paul + Lockaby, Monte) + - silence PHP warnings in function.fetch.php (Eduardo, + Monte) + - added get_config_vars(), same basic functionality as + get_template_vars() (Monte) + - update get_template_vars() to be able to get + individual vars (Monte) + - fix minor logic in _fetch_template_info (Dennis Gearon, + Monte) + - fix cache groups with compile_id set (Monte) + - add support for merging appended vars (messju, Monte) + - allow null as function attribute value + (André Rabold, Monte) + - support $foo->bar[index] syntax (Monte) + - add get_registered_object function (messju, Monte) + - treat unrecognized param attribute syntax as string (Monte) + - support $smarty.const.$foo syntax (messju, Monte) + - remove E_NOTICE warnings from debug.tpl, + escape modifier (Kanstantin, Monte) + - don't count non-ascii chars in count_words modifier + (Kanstantin, Monte) + - clean up param calls to _parse_var and _parse_attrs (Monte) + - define $template_source var, elude possible warning + (Monte) + - fix syntax problem with evaluating PHP constants (Monte) + - add @ and === as valid if statement tokens (Monte) + - enable error messages for config_load errors, + use $this->config_class for loading class name (Monte) + - fix html_options to not escape already escaped entities (Monte) + - send Last-Modified header on cache creation (Monte) + - check strict syntax of function attributes (Monte) + - dropped support for modifers on object parameters, + added support for objects as modifier parameters (Monte) + - fixed bug with decimal numbers in if statements (Monte) + +Version 2.4.2 (Feb 11, 2003) +---------------------------- + - support embedded variables in objects (Monte) + - fix bug with objects with no properties (M Mohr, Monte) + - support full dollar var syntax in quoted text (Monte) + - fixed bug in $smarty.const.FOO introduced in 2.4.1 (M + Mohr, Monte) + +Version 2.4.1 (Feb 6, 2003) +--------------------------- + + - ignore case in IF statements (Rainer Collet, Monte) + - treat undefined constants as null (Ferdinand Beyer, Monte) + - fix problem with inserts and nested fetches + (Rainer Collet, Monte) + - added support for passing params to include_php + (Tim Riley, Monte) + - added support for math operators in if statements (Monte) + - added support for $foo->bar[$x].blah syntax (Monte) + +Version 2.4.0 (Feb 2, 2003) +--------------------------- + + - fix known problems with php tag handling in templates + (recursion, echoing xml tags) (Monte) + - add support for object registration (Monte) + - add debug template to secure_dir, add template_dir + to secure_dir by default (Ferdinand Beyer, Monte) + - added support for assigned object access (Monte) + - fixed bug with directories named '0' (Frank Bauer, Monte) + - add javascript parameter to escape modifier (Monte) + - added calling function line numbers to syntax error + messages in compiler (Monte) + - added support for modifiers to function calls (Monte) + - support return value for custom functions + instead of echoing (but echo still works) (Monte) + - added direct access to constants + via $smarty.const.FOO (Monte) + - added support for passing modifiers + to static values (Monte) + - fix up regex code in compiler, more accurate and + maintainable (Monte) + - added day_value_format to html_select_date (Marcus + Bointon, Monte) + - assigned variables are no longer in global + namespace, saving extract() calls and speeding + up fetch() and display() linearly with no. of + assigned variables (Monte) + - added trimwhitespace output filter to dist. (Monte) + - fix popup function to allow newlines in text (Monte) + - escape html entities in html_options (Monte) + - fixed bug with label for html_options (Monte) + - added config_load API function (Monte) + - added caching to config file loading (Monte) + - added "extra" parameter to mailto function (Monte, + Massimiliano Perantoni) + - added mailto plugin to dist. (Monte) + +Version 2.3.1 (Nov 19, 2002) +---------------------------- + + - added optgroup support to html_options (Monte, Robert + Amos) + - set mtime on compile files so they match source + files (Monte, Peter Bowen) + - added proper support for open_basedir setting + (Monte, Alessandro Astarita) + - added strip variable modifier, updated docs (Monte) + - fixed access to $smarty.x variables as arrays. (Andrei) + - fixed errors with example setup docs (Monte, Matthew + Hagerty) + - added textformat block function (Monte) + +Version 2.3.0 (Aug 7, 2002) +--------------------------- + + - added assign_by_ref() and append_by_ref() functions + (Bob Silva, Monte) + - changed default warning type for plugin errors from + E_USER_WARNING to E_USER_ERROR (Monte) + - added $all_extra, $hour_extra, $minute_extra, + $second_extra and $meridian_extra parameters to + html_select_time function (Rainer Collet, Monte) + - update debug console to print objects (Simon Willison, + Monte) + - fix Config_File class to not error when there are no + sections (Peter Kmet, Monte) + - add default modifier logic (Monte) + - updated popup_init to be xhtml compliant (Tom Oram, Monte) + - fix filename bug with windows (Gary Loescher, Monte) + - add ability to supply expire time in seconds when clearing + cache or compile files (Monte) + - add {debug} plugin to distribution (Monte) + - fixed bug with insert tags, loading from "script" attribute + when caching is enabled (Monte) + - fix bug with debug_tpl file path with Windows (.SMK., Monte) + - fix append() function with string/array problem (Monte) + +Version 2.2.0 (July 11, 2002) +----------------------------- + + - make debug.tpl work with any delimiter (Monte) + - change logic in assign() and append() to test var names + against != '' instead of empty() (Monte) + - fix PHP notice in append() function (Monte) + - allow $plugins_dir to be an array of directories + (Andreas Kossmeier, Monte) + - move debug.tpl to SMARTY_DIR, add to constructor (Monte) + - fixed warning message in function.assign_debug_info (Monte) + - fixed $template_dir, $compile_dir, $cache_dir, $config_dir, + $plugin_dir to respect include_path (Monte) + - fixed warning message with output filter array (Monte) + - add optional 2nd parameter to date_format, used as + the default date if the passed date is empty (Monte) + - gave $reset a default value in cycle plugin (Monte) + - fixed warnings with html_select_date and timestamp + functions (Monte) + - added support for sub directory exlusion format (Monte) + - added support for grouping by cache_id, compile_id + and segments thereof (Monte) + - changed cache and compile files to human readable + format (Monte) + - remove overlib.js file from distribution (Monte) + - fixed bug with 304 Not Modified response sending + content (Monte) + - fixed cycle function to respect delimiter after + initial setting (Monte) + - update $GLOBALS references to work properly with + track_globals settings (Michal Prinke, Monte) + - fixed bug in math function with call to assign + (Grigory V. Kareev, Monte) + - optimized for loops with count() function calls (Monte) + - add month_value_format attribute to html_select_date + plugin (Gary Loescher, Monte) + - made it possible to use simple variables inside [] for + indexing. (Andrei) + - added "once" attribute to {include_php}. (Monte) + +Version 2.1.1 +------------- + - added cycle function. (Monte) + - fixed bug with resource testing, and include_path. (Monte) + - fixed a bug with register_outputfilter function. (Monte) + +Version 2.1.0 +------------- + + - introduced output filters. (Andrei) + - changed the way filters are loaded, added load_filter() + API function and $autoload_filters variable. (Andrei) + - added caching logic for expire times per cache file + (Norbert Rocher, Monte) + - fixed html_select_date when field separator is "/" + (Roberto Berto, Monte) + - added YYYY-MM-DD format support to html_select_date + (Jan Rosier, Monte) + - fixed cache_lifetime logic bug, also made -1 = never + expire (Monte) + - fixed directory separator issue for Windows. (Andrei) + - added ability to use simple variables as array indices or + object properties. (Andrei) + - added ability to unregister pre/postfilters plugins at + runtime. (Andrei) + - added 'htmlall' attribute to escape modifier. (Monte) + - added template_exists() API function. (Andrei) + - fixed a problem with using dynamic values for 'file' + attribute of {include_php} tag. (Andrei) + - added $smarty.template variable. (Andrei) + - fixed several plugins that would not work if the plugin + directory was not the default one. (Andrei) + - implemented support for block functions. (Andrei) + - made it possible to assign variables in pre/postfilter + plugins. (Andrei) + +Version 2.0.1 +------------- + - rename plugin .make_timestamp.php to shared.make_timestamp.php. + (Monte) + - changed crc32() generated values, replace '-' with 'N'. (Monte) + - added support for +/- N syntax in html_select_date year values. + (Monte) + - fixed behavior of inserts with script attribute. (Andrei) + - fixed bug with $smarty.cookies and $smarty.server. (Andrei) + - wordwrap and indent are missing from 2.0 release, now fixed. + (Monte) + - removed show_info_header and show_info_include variables. (Monte) + +Version 2.0.0 +------------- + - added "eval" function plugin for evaluating variables as + templates. (Monte) + - removed $tpl_file_ext class variable, no longer used. (Monte) + - added "hex" and "hexentity" escape types to escape modifier. + (Monte) + - removed dependency on PEAR. (Andrei) + - update popup_init to accept src attribute. (Monte, Duncan Forrest) + - implemented several optimizations, speeding up Smarty + significantly in most cases. (Andrei,Monte) + - implemented plugin architecture. (Andrei) + - added wordwrap and indent modifiers. (Monte) + - added support for 'If-Modified-Since' headers for cached content. + (Monte) + - removed insert_tag_check class variable, no longer needed. (Monte) + - optimized cache fetches by scanning for insert tags only if they + exist. (Monte) + - fixed bugs in overlib. (Monte, Duncan Forrest) + - fixed a problem with compile_id usage. (Andrei) + - fixed problem with using assigned vars with {include_php ...} + filepath. (Monte) + +Version 1.5.2 +------------- + - added Smarty object as fifth argument for template resource functions. + (Monte) + - fixed a bug with incorrectly combined cache and compile id in + clear_cache(). (Andrei) + - fixed bug in smarty_make_timestamp introduced in PHP 4.1.0. (Monte) + - fixed bug with cached insert debug timing. (Monte) + - added 'script' attribute to {insert..} which specifies the script that + the insert function can be found in. (Andrei) + - added default template function handler. (Monte) + +Version 1.5.1 +------------- + - removed error message from the generic _read_file() method, the caller + should take care of that. (Andrei) + - fixed a bug with incorrectly combined cache and compile id. (Andrei) + +Version 1.5.0 +------------- + - added include_php built-in function, documented. (Monte) + - added trusted_dir functionality, documented. (Monte) + - consolidated secure_dir tests to one function. (Monte) + - prepended _smarty_ to variable names in fetch() class function to avoid + namespace conflicts. (Monte) + - introduced $compile_id class variable that can be used to set persistent + compile identifier across multiple display calls, documented. (Andrei) + - fixed bug with concatenated null cache and compile identifiers. (Andrei) + - added $smarty.section.* syntax for accessing section properties, + documented. (Andrei) + - added custom cache handling function ability, documented. (Monte) + - added assign attribute to include, include_php, insert, fetch, math, and + counter functions, documented. (Monte) + - fixed bug with fetch testing for local file when http address. (Monte) + - fixed bug with counter and skipval setting. (Monte) + - made {config_load ...} merge globals from each config file only once per + scope, thus avoiding several problems. (Andrei) + - added {foreach ...} tag that can be used to iterate through + non-sequential and associative arrays, documented. (Andrei) + - speeded up section property access a bit. (Andrei) + - removed $smarty variable from storage used by normal template variables, + to prevent any problems. (Andrei) + - fixed a bug that could cause parse error with quotes inside literal + blocks. (Andrei, Alexander Belonosov) + - added 'field_array' attribute to html_select_time function, documented. + (Andrei, Michael Caplan) + - documented {section} "max" attribute. (Monte) + - fixed notice message in Smarty_Compiler.class.php. (Monte) + - fixed bug with clear_cache introduced in 1.4.6, third parameter should + default to null. (Monte) + - updated Config_File class to support '\' path separator in OS/2. (Monte, + Francesco Cipriani) + - removed secure_ext setting (not used). (Monte) + - made cache reading process more efficient. (Monte) + - fixed bug, is_cached() now supports new 1.4.6 caching behavior. (Monte) + - update FAQ with mailing list Reply-To header FAQ. (Monte) + - supress error messages for fopen(), fix cache to regenerate if cache + file is not available (i.e. cluster race condition). (Monte) + - added index key example to QUICKSTART guide. (Monte) + +Version 1.4.6 +------------- + - fixed bug with {assign ...} when passing an empty value. (Monte) + - add more warning message fixes. (Monte, Tara Johnson) + - documentation updates. (Monte) + - update fetch function to give proper warning when fetching a non-readable + or non-existant file. (Monte) + - fixed problem with newline at the end of included templates (Monte, Andrei) + - added feature to regenerate cache if compile_check is enabled and an + involved template or config file gets modified. (Monte) + - added DEBUG execution times to included files: REQUIRES updated debug.tpl + file! (Monte) + - added support for hidden config variables that cannot be read by + templates. (Andrei) + - added execution time to DEBUG console, total and inserts. (Monte) + - fixed bug where DEBUG console would not appear with cached content. (Monte) + - added support for postfilter functions that are applied to compiled + template right after compilation. (Andrei) + - fixed the name of clear_compile_tpl() API function to clear_compiled_tpl. + (Andrei) + - added fix for removing comments so that the line numbers are reported + correctly in case of errors. (patch from Anders Janson) + - made html_options output xhtml compatible code. (Monte, Arnaud Limbourg) + +Version 1.4.5 +------------- + - update FAQ with index of questions at the top + - update overlib to 3.50, adjust addon code so that the overlib.js + file isn't modified, and not using the mini one. (Monte) + - added many more options to html_select_date. (Alexander Skwar, Andrei) + - added support for generating different compiled templates from the same + source template. (Hans-Peter Oeri, Andrei) + - modified Smarty to pass itself to insert functions as the second + parameter. (Andrei) + - modified Smarty to pass itself to prefilter functions as the second + parameter. (Andrei) + - fixed syntax error when including a non-existant template with security + enabled. (Monte) + - fixed comments handling to allow commenting out template blocks. (Andrei) + - implemented named capture buffers, with results accessible via + $smarty.capture.<name>. (Andrei) + - added ability to index arrays directly by numbers. (Andrei) + - fixed bug with SMARTY_DIR not prepended to Config_File include. (Monte) + +Version 1.4.4 +------------- + - fixed problem with including insecure templates with security enabled. + (Monte) + - numerous documentation updates. (Monte) + - added ENT_QUOTES to escapement of html. (Monte, Sam Beckwith) + - implemented access to request variables via auto-assigned $smarty + template variable. (Andrei) + - fixed a bug with parsing function arguments inside {if} tags if a comma + was present. (Andrei) + - updated debug console with config file vars. (Monte) + - added SMARTY_DIR constant as an alternative to relying on include_path. + (Monte) + - added popup_init and popup functions (requires overlib.js). (Monte) + - updated debug console with config file vars. (Monte) + - added debugging url control. (Monte) + - added 'quotes' type to escape modifier. (Monte, Mike Krus) + - added 'total' and 'iteration' section properties. (Andrei) + - added 'start', 'max', and 'step' section attributes/properties. (Andrei) + - fixed a bug with security checking of functions inside {if} tags. + (Andrei) + - fixed a bug in Config_File that would incorrectly booleanize values that + weren't really booleans. (Andrei) + +Version 1.4.3 +------------- + - added regex_replace modifier, documented. (Monte) + - added debugging console feature and custom function assign_debug_info, + documented. (Monte) + - added 'scope' attribute for {config_load}, 'global' is now deprecated but + is still supported. (Andrei) + - reduced template symbol table pollution by moving config array into the + class itself. (Andrei) + - fixed a bug with passing quoted arguments to modifiers inside {if} + statements. (Andrei, Sam Beckwith) + - added security features for third party template editing, documented + (Monte) + - added assign custom function, documented. (Monte) + - fixed bug with template header using version instead of _version. (Monte) + - fixed a problem with putting $ followed by numbers inside {strip} and + {/strip} tags. (Andrei) + - fixed Config_File class to allow empty config paths (defaults to current + directory). (Andrei) + +Version 1.4.2 +------------- + - move $version to internal variable, remove from docs. (Monte) + - cleaned up compiled templates global scope by moving some variables into + the class itself. (Andrei) + - fixed a bug that would not allow referring to a section in the including + file from the included file. (Andrei) + - configs directory missing from 1.4.1 release, added back in. (Monte) + - added windows include_path setup instructions to FAQ & QUICKSTART. + (Monte) + +Version 1.4.1 +------------- + - fix LOCK_EX logic for all windows platforms (Monte) + - fixed indexing by section properties with the new syntax. (Andrei) + - updated Smarty to use absolute paths when requiring/including Smarty + components. (Andrei, John Lim) + +Version 1.4.0 +------------- + - added {capture}{/capture} function, documented (Monte) + - added {counter} function, documented (Monte) + +Version 1.4.0b2 +--------------- + - fixed issue in Config_File.class with referencing blank sections (Andrei) + - fixed problem with passing variables to included files (Andrei) + - fixed resource path recognition for windows (Monte) + +Version 1.4.0b1 +--------------- + - added "componentized templates" tip into documentation (Monte) + - added {php}{/php} tags for embedding php code into templates (Monte) + - changed default value of $show_info_header to false (Monte) + - implemented '->' syntax for accessing properties of objects passed to the + template. (Andrei) + - allowed custom functions to receive Smarty object as the second + parameter; this can be used to dynamically change template variables, for + example. (Andrei) + - added custom compiler functions support, register_compiler_function() and + unregister_compiler_function() API functions. (Andrei, Ivo Jansch). + - updated GLOBAL_ASSIGN to take SCRIPT_NAME from HTTP_SERVER_VARS + instead of global variable. You can also assign several variables + in one shot with an array. (Monte, Roman Neuhauser) + - added template prefilters, register_prefilter() and + unregister_prefilter() API functions. (Monte) + - added RELEASE_NOTES file to distribution. (Monte) + - moved CREDITS out of manual into its own file. (Monte) + - added register_resource() and unregister_resource() API functions. (Monte) + - changed the syntax of indexing template variables, thus supporting + structures of arbitrary complexity; supplied fix_vars.php script to fix + old syntax. (Andrei) + - added $insert_tag_check to speed up cached pages if {insert ...} is not + used. (Monte) + - added $compiler_class variable to allow specifying a different compiler + class. (Andrei) + - changed Smarty to compile templates at runtime, allowing for arbitrary + template resources. (Monte) + - added fix for LOCK_EX under Windows and changed a couple of file + permissions for security. (Monte, Fernando Nunes) + - allow arbitrary date strings to date_format, html_select_date and + html_select_time (Monte) + +Version 1.3.2 +------------- + - fixed a bug that caused some nested includes to loop infinitely. (Andrei) + - added optional HTML header to output. (Monte) + - significantly improved config_load performance. (Andrei) + - added format attribute to math function. (Monte) + - added html_select_time custom function. (Andrei) + - fixed minor PHP warning when attempting to unset an unset variable + (Monte) + - added count_characters, count_words, count_sentences, count_paragraphs + modifiers (Monte) + +Version 1.3.1pl1 +-------------- + - bug fix, recovered missing _syntax_error function (Monte) + +Version 1.3.1 +------------- + - document first, last, index_prev, index_next (Monte) + - added 'first' and 'last' section properties. (Andrei) + - split out compiling code to separate class for faster template execution + time (Monte) + - fixed a couple of minor PHP warnings (Monte) + - added and documented unregister_modifier() and unregister_function() API + calls. (Monte) + - added and documented 'fetch' and 'math' functions. (Monte) + - added ability to index looped variables by section properties, e.g. + $foo.index_prev/bar. (Andrei) + - added index_prev and index_next section properties. (Andrei) + - fixed issue with php executing in literal blocks. (Monte) + +Version 1.3.0 +------------- + - moved license from GPL to LGPL (Monte) + - implemented workaround for PHP "feature" that eats carriage returns + if the PHP tag is at the end of the line. (Andrei) + - removed $allow_php, added $php_handling logic (Monte) + - added file locking to prevent reader/writer problem. (Andrei) + - made Smarty catch unimplemented modifiers and custom functions and output + error messages during compilation instead of failing during run time. + (Andrei) + - removed short-tags at the top of the smarty scripts (Monte) + - added register_function() and register_modifier() API calls to make + registering stuff easier. (Andrei) + - added template results caching capability. (Monte, Andrei) + - added optional 'options' attribute to html_options custom function + that allows passing associative arrays for values/output. (Andrei) + - modifier arguments can now contain '|' and ':' characters inside quoted + strings. (Andrei) + +Version 1.2.2 +------------- + - fixed bug that would not respect nested template directories and would + put all compiled files into top-level one. (Andrei) + - fixed bug using $PHP_VERSION instead of environment var PHP_VERSION. + (Monte) + - a couple small warning fixes. (Monte) + +Version 1.2.1 +------------- + - added $compile_dir, removed $compile_dir_ext, simplified usage. (Monte) + - added tips & tricks chapter to documentation. (Monte) + - misc documentation updates. (Monte) + +Version 1.2.0 +------------- + - updated documentation (Monte) + - added file and line number information to syntax error messages. (Andrei) + - added ability to index template vars by a key. (Andrei) + +Version 1.1.0 +------------- + - misc documentation changes, official stable release + +Version 1.0b +------------ + - fixed the bug that prevented using non-array values for 'loop' attribute. + (Andrei) + - many misc documentation changes & additions (Monte) + +Version 1.0a +------------ + - fixed bug that caused templates to recompile every time (Monte) + +Version 1.0 +------------ + - initial release + +/* vim: set et tw=64 ft=changelog: */ diff --git a/BSF/include/smarty/README b/BSF/include/smarty/README new file mode 100644 index 000000000..6e7c93c56 --- /dev/null +++ b/BSF/include/smarty/README @@ -0,0 +1,85 @@ +NAME: + + Smarty - the PHP compiling template engine + +VERSION: 2.6.19 + +AUTHORS: + + Monte Ohrt <monte at ohrt dot com> + Andrei Zmievski <andrei@php.net> + +MAILING LISTS: + + We have a few mailing lists. "discussion" for you to share your ideas or ask + questions, "developers" for those interested in the development efforts of Smarty, + and "svn" for those that would like to track the updates made in the svn + repository. + + send a blank e-mail message to: + smarty-discussion-subscribe@googlecode.com(subscribe to the general discussion list) + smarty-discussion-unsubscribe@googlecode.com (unsubscribe from the general discussion list) + smarty-discussion-digest-subscribe@googlecode.com (subscribe to digest) + smarty-discussion-digest-unsubscribe@googlecode.com (unsubscribe from digest) + smarty-developers-subscribe@googlecode.com (subscribe to the dev list) + smarty-developers-unsubscribe@googlecode.com (unsubscribe from the dev list) + smarty-svn-subscribe@googlecode.com (subscribe to the svn list) + smarty-svn-unsubscribe@googlecode.com (unsubscribe from the svn list) + + You can also browse the mailing list archives at + http://groups.google.com/group/smarty-discussion + http://groups.google.com/group/smarty-developers + + and the OLD list archives at + http://marc.theaimsgroup.com/?l=smarty&r=1&w=2 + +SYNOPSIS: + + require("Smarty.class.php"); + + $smarty = new Smarty; + + $smarty->assign("Title","My Homepage"); + $smarty->assign("Names",array("John","Gary","Gregg","James")); + + $smarty->display("index.tpl"); + + +DESCRIPTION: + + What is Smarty? + + Smarty is a template engine for PHP. Many other template engines for PHP + provide basic variable substitution and dynamic block functionality. + Smarty takes a step further to be a "smart" template engine, adding + features such as configuration files, template functions, and variable + modifiers, and making all of this functionality as easy as possible to + use for both programmers and template designers. Smarty also converts + the templates into PHP scripts, eliminating the need to parse the + templates on every invocation. This makes Smarty extremely scalable and + manageable for large application needs. + + Some of Smarty's features: + + * it is extremely fast + * no template parsing overhead, only compiles once. + * it is smart about recompiling only the template files that have + changed. + * the template language is remarkably extensible via the plugin + architecture. + * configurable template delimiter tag syntax, so you can use + {}, {{}}, <!--{}-->, or whatever you like. + * built-in caching of template output. + * arbitrary template sources (filesystem, databases, etc.) + * template if/elseif/else/endif constructs are passed to the PHP parser, + so the if syntax can be as simple or as complex as you like. + * unlimited nesting of sections, conditionals, etc. allowed + * it is possible to embed PHP code right in your template files, + although not recommended and doubtfully needed since the engine + is so customizable. + * and many more. + +COPYRIGHT: + Copyright (c) 2001-2005 New Digital Group, Inc. All rights reserved. + This software is released under the GNU Lesser General Public License. + Please read the disclaimer at the top of the Smarty.class.php file. diff --git a/BSF/include/smarty/libs/Config_File.class.php b/BSF/include/smarty/libs/Config_File.class.php new file mode 100644 index 000000000..89ba41c45 --- /dev/null +++ b/BSF/include/smarty/libs/Config_File.class.php @@ -0,0 +1,389 @@ +<?php + +/** + * Config_File class. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @link http://smarty.php.net/ + * @version 2.6.19 + * @copyright Copyright: 2001-2005 New Digital Group, Inc. + * @author Andrei Zmievski <andrei@php.net> + * @access public + * @package Smarty + */ + +/* $Id$ */ + +/** + * Config file reading class + * @package Smarty + */ +class Config_File { + /**#@+ + * Options + * @var boolean + */ + /** + * Controls whether variables with the same name overwrite each other. + */ + var $overwrite = true; + + /** + * Controls whether config values of on/true/yes and off/false/no get + * converted to boolean values automatically. + */ + var $booleanize = true; + + /** + * Controls whether hidden config sections/vars are read from the file. + */ + var $read_hidden = true; + + /** + * Controls whether or not to fix mac or dos formatted newlines. + * If set to true, \r or \r\n will be changed to \n. + */ + var $fix_newlines = true; + /**#@-*/ + + /** @access private */ + var $_config_path = ""; + var $_config_data = array(); + /**#@-*/ + + /** + * Constructs a new config file class. + * + * @param string $config_path (optional) path to the config files + */ + function Config_File($config_path = NULL) + { + if (isset($config_path)) + $this->set_path($config_path); + } + + + /** + * Set the path where configuration files can be found. + * + * @param string $config_path path to the config files + */ + function set_path($config_path) + { + if (!empty($config_path)) { + if (!is_string($config_path) || !file_exists($config_path) || !is_dir($config_path)) { + $this->_trigger_error_msg("Bad config file path '$config_path'"); + return; + } + if(substr($config_path, -1) != DIRECTORY_SEPARATOR) { + $config_path .= DIRECTORY_SEPARATOR; + } + + $this->_config_path = $config_path; + } + } + + + /** + * Retrieves config info based on the file, section, and variable name. + * + * @param string $file_name config file to get info for + * @param string $section_name (optional) section to get info for + * @param string $var_name (optional) variable to get info for + * @return string|array a value or array of values + */ + function get($file_name, $section_name = NULL, $var_name = NULL) + { + if (empty($file_name)) { + $this->_trigger_error_msg('Empty config file name'); + return; + } else { + $file_name = $this->_config_path . $file_name; + if (!isset($this->_config_data[$file_name])) + $this->load_file($file_name, false); + } + + if (!empty($var_name)) { + if (empty($section_name)) { + return $this->_config_data[$file_name]["vars"][$var_name]; + } else { + if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name])) + return $this->_config_data[$file_name]["sections"][$section_name]["vars"][$var_name]; + else + return array(); + } + } else { + if (empty($section_name)) { + return (array)$this->_config_data[$file_name]["vars"]; + } else { + if(isset($this->_config_data[$file_name]["sections"][$section_name]["vars"])) + return (array)$this->_config_data[$file_name]["sections"][$section_name]["vars"]; + else + return array(); + } + } + } + + + /** + * Retrieves config info based on the key. + * + * @param $file_name string config key (filename/section/var) + * @return string|array same as get() + * @uses get() retrieves information from config file and returns it + */ + function &get_key($config_key) + { + list($file_name, $section_name, $var_name) = explode('/', $config_key, 3); + $result = &$this->get($file_name, $section_name, $var_name); + return $result; + } + + /** + * Get all loaded config file names. + * + * @return array an array of loaded config file names + */ + function get_file_names() + { + return array_keys($this->_config_data); + } + + + /** + * Get all section names from a loaded file. + * + * @param string $file_name config file to get section names from + * @return array an array of section names from the specified file + */ + function get_section_names($file_name) + { + $file_name = $this->_config_path . $file_name; + if (!isset($this->_config_data[$file_name])) { + $this->_trigger_error_msg("Unknown config file '$file_name'"); + return; + } + + return array_keys($this->_config_data[$file_name]["sections"]); + } + + + /** + * Get all global or section variable names. + * + * @param string $file_name config file to get info for + * @param string $section_name (optional) section to get info for + * @return array an array of variables names from the specified file/section + */ + function get_var_names($file_name, $section = NULL) + { + if (empty($file_name)) { + $this->_trigger_error_msg('Empty config file name'); + return; + } else if (!isset($this->_config_data[$file_name])) { + $this->_trigger_error_msg("Unknown config file '$file_name'"); + return; + } + + if (empty($section)) + return array_keys($this->_config_data[$file_name]["vars"]); + else + return array_keys($this->_config_data[$file_name]["sections"][$section]["vars"]); + } + + + /** + * Clear loaded config data for a certain file or all files. + * + * @param string $file_name file to clear config data for + */ + function clear($file_name = NULL) + { + if ($file_name === NULL) + $this->_config_data = array(); + else if (isset($this->_config_data[$file_name])) + $this->_config_data[$file_name] = array(); + } + + + /** + * Load a configuration file manually. + * + * @param string $file_name file name to load + * @param boolean $prepend_path whether current config path should be + * prepended to the filename + */ + function load_file($file_name, $prepend_path = true) + { + if ($prepend_path && $this->_config_path != "") + $config_file = $this->_config_path . $file_name; + else + $config_file = $file_name; + + ini_set('track_errors', true); + $fp = @fopen($config_file, "r"); + if (!is_resource($fp)) { + $this->_trigger_error_msg("Could not open config file '$config_file'"); + return false; + } + + $contents = ($size = filesize($config_file)) ? fread($fp, $size) : ''; + fclose($fp); + + $this->_config_data[$config_file] = $this->parse_contents($contents); + return true; + } + + /** + * Store the contents of a file manually. + * + * @param string $config_file file name of the related contents + * @param string $contents the file-contents to parse + */ + function set_file_contents($config_file, $contents) + { + $this->_config_data[$config_file] = $this->parse_contents($contents); + return true; + } + + /** + * parse the source of a configuration file manually. + * + * @param string $contents the file-contents to parse + */ + function parse_contents($contents) + { + if($this->fix_newlines) { + // fix mac/dos formatted newlines + $contents = preg_replace('!\r\n?!', "\n", $contents); + } + + $config_data = array(); + $config_data['sections'] = array(); + $config_data['vars'] = array(); + + /* reference to fill with data */ + $vars =& $config_data['vars']; + + /* parse file line by line */ + preg_match_all('!^.*\r?\n?!m', $contents, $match); + $lines = $match[0]; + for ($i=0, $count=count($lines); $i<$count; $i++) { + $line = $lines[$i]; + if (empty($line)) continue; + + if ( substr($line, 0, 1) == '[' && preg_match('!^\[(.*?)\]!', $line, $match) ) { + /* section found */ + if (substr($match[1], 0, 1) == '.') { + /* hidden section */ + if ($this->read_hidden) { + $section_name = substr($match[1], 1); + } else { + /* break reference to $vars to ignore hidden section */ + unset($vars); + $vars = array(); + continue; + } + } else { + $section_name = $match[1]; + } + if (!isset($config_data['sections'][$section_name])) + $config_data['sections'][$section_name] = array('vars' => array()); + $vars =& $config_data['sections'][$section_name]['vars']; + continue; + } + + if (preg_match('/^\s*(\.?\w+)\s*=\s*(.*)/s', $line, $match)) { + /* variable found */ + $var_name = rtrim($match[1]); + if (strpos($match[2], '"""') === 0) { + /* handle multiline-value */ + $lines[$i] = substr($match[2], 3); + $var_value = ''; + while ($i<$count) { + if (($pos = strpos($lines[$i], '"""')) === false) { + $var_value .= $lines[$i++]; + } else { + /* end of multiline-value */ + $var_value .= substr($lines[$i], 0, $pos); + break; + } + } + $booleanize = false; + + } else { + /* handle simple value */ + $var_value = preg_replace('/^([\'"])(.*)\1$/', '\2', rtrim($match[2])); + $booleanize = $this->booleanize; + + } + $this->_set_config_var($vars, $var_name, $var_value, $booleanize); + } + /* else unparsable line / means it is a comment / means ignore it */ + } + return $config_data; + } + + /**#@+ @access private */ + /** + * @param array &$container + * @param string $var_name + * @param mixed $var_value + * @param boolean $booleanize determines whether $var_value is converted to + * to true/false + */ + function _set_config_var(&$container, $var_name, $var_value, $booleanize) + { + if (substr($var_name, 0, 1) == '.') { + if (!$this->read_hidden) + return; + else + $var_name = substr($var_name, 1); + } + + if (!preg_match("/^[a-zA-Z_]\w*$/", $var_name)) { + $this->_trigger_error_msg("Bad variable name '$var_name'"); + return; + } + + if ($booleanize) { + if (preg_match("/^(on|true|yes)$/i", $var_value)) + $var_value = true; + else if (preg_match("/^(off|false|no)$/i", $var_value)) + $var_value = false; + } + + if (!isset($container[$var_name]) || $this->overwrite) + $container[$var_name] = $var_value; + else { + settype($container[$var_name], 'array'); + $container[$var_name][] = $var_value; + } + } + + /** + * @uses trigger_error() creates a PHP warning/error + * @param string $error_msg + * @param integer $error_type one of + */ + function _trigger_error_msg($error_msg, $error_type = E_USER_WARNING) + { + trigger_error("Config_File error: $error_msg", $error_type); + } + /**#@-*/ +} + +?> diff --git a/BSF/include/smarty/libs/Smarty.class.php b/BSF/include/smarty/libs/Smarty.class.php new file mode 100644 index 000000000..6b893dec8 --- /dev/null +++ b/BSF/include/smarty/libs/Smarty.class.php @@ -0,0 +1,1968 @@ +<?php + +/** + * Project: Smarty: the PHP compiling template engine + * File: Smarty.class.php + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * For questions, help, comments, discussion, etc., please join the + * Smarty mailing list. Send a blank e-mail to + * smarty-general-subscribe@lists.php.net + * + * @link http://smarty.php.net/ + * @copyright 2001-2005 New Digital Group, Inc. + * @author Monte Ohrt <monte at ohrt dot com> + * @author Andrei Zmievski <andrei@php.net> + * @package Smarty + * @version 2.6.19 + */ + +/* $Id$ */ + +/** + * DIR_SEP isn't used anymore, but third party apps might + */ +if(!defined('DIR_SEP')) { + define('DIR_SEP', DIRECTORY_SEPARATOR); +} + +/** + * set SMARTY_DIR to absolute path to Smarty library files. + * if not defined, include_path will be used. Sets SMARTY_DIR only if user + * application has not already defined it. + */ + +if (!defined('SMARTY_DIR')) { + define('SMARTY_DIR', dirname(__FILE__) . DIRECTORY_SEPARATOR); +} + +if (!defined('SMARTY_CORE_DIR')) { + define('SMARTY_CORE_DIR', SMARTY_DIR . 'internals' . DIRECTORY_SEPARATOR); +} + +define('SMARTY_PHP_PASSTHRU', 0); +define('SMARTY_PHP_QUOTE', 1); +define('SMARTY_PHP_REMOVE', 2); +define('SMARTY_PHP_ALLOW', 3); + +/** + * @package Smarty + */ +class Smarty +{ + /**#@+ + * Smarty Configuration Section + */ + + /** + * The name of the directory where templates are located. + * + * @var string + */ + var $template_dir = 'templates'; + + /** + * The directory where compiled templates are located. + * + * @var string + */ + var $compile_dir = 'templates_c'; + + /** + * The directory where config files are located. + * + * @var string + */ + var $config_dir = 'configs'; + + /** + * An array of directories searched for plugins. + * + * @var array + */ + var $plugins_dir = array('plugins'); + + /** + * If debugging is enabled, a debug console window will display + * when the page loads (make sure your browser allows unrequested + * popup windows) + * + * @var boolean + */ + var $debugging = false; + + /** + * When set, smarty does uses this value as error_reporting-level. + * + * @var boolean + */ + var $error_reporting = null; + + /** + * This is the path to the debug console template. If not set, + * the default one will be used. + * + * @var string + */ + var $debug_tpl = ''; + + /** + * This determines if debugging is enable-able from the browser. + * <ul> + * <li>NONE => no debugging control allowed</li> + * <li>URL => enable debugging when SMARTY_DEBUG is found in the URL.</li> + * </ul> + * @link http://www.foo.dom/index.php?SMARTY_DEBUG + * @var string + */ + var $debugging_ctrl = 'NONE'; + + /** + * This tells Smarty whether to check for recompiling or not. Recompiling + * does not need to happen unless a template or config file is changed. + * Typically you enable this during development, and disable for + * production. + * + * @var boolean + */ + var $compile_check = true; + + /** + * This forces templates to compile every time. Useful for development + * or debugging. + * + * @var boolean + */ + var $force_compile = false; + + /** + * This enables template caching. + * <ul> + * <li>0 = no caching</li> + * <li>1 = use class cache_lifetime value</li> + * <li>2 = use cache_lifetime in cache file</li> + * </ul> + * @var integer + */ + var $caching = 0; + + /** + * The name of the directory for cache files. + * + * @var string + */ + var $cache_dir = 'cache'; + + /** + * This is the number of seconds cached content will persist. + * <ul> + * <li>0 = always regenerate cache</li> + * <li>-1 = never expires</li> + * </ul> + * + * @var integer + */ + var $cache_lifetime = 3600; + + /** + * Only used when $caching is enabled. If true, then If-Modified-Since headers + * are respected with cached content, and appropriate HTTP headers are sent. + * This way repeated hits to a cached page do not send the entire page to the + * client every time. + * + * @var boolean + */ + var $cache_modified_check = false; + + /** + * This determines how Smarty handles "<?php ... ?>" tags in templates. + * possible values: + * <ul> + * <li>SMARTY_PHP_PASSTHRU -> print tags as plain text</li> + * <li>SMARTY_PHP_QUOTE -> escape tags as entities</li> + * <li>SMARTY_PHP_REMOVE -> remove php tags</li> + * <li>SMARTY_PHP_ALLOW -> execute php tags</li> + * </ul> + * + * @var integer + */ + var $php_handling = SMARTY_PHP_PASSTHRU; + + /** + * This enables template security. When enabled, many things are restricted + * in the templates that normally would go unchecked. This is useful when + * untrusted parties are editing templates and you want a reasonable level + * of security. (no direct execution of PHP in templates for example) + * + * @var boolean + */ + var $security = false; + + /** + * This is the list of template directories that are considered secure. This + * is used only if {@link $security} is enabled. One directory per array + * element. {@link $template_dir} is in this list implicitly. + * + * @var array + */ + var $secure_dir = array(); + + /** + * These are the security settings for Smarty. They are used only when + * {@link $security} is enabled. + * + * @var array + */ + var $security_settings = array( + 'PHP_HANDLING' => false, + 'IF_FUNCS' => array('array', 'list', + 'isset', 'empty', + 'count', 'sizeof', + 'in_array', 'is_array', + 'true', 'false', 'null'), + 'INCLUDE_ANY' => false, + 'PHP_TAGS' => false, + 'MODIFIER_FUNCS' => array('count'), + 'ALLOW_CONSTANTS' => false + ); + + /** + * This is an array of directories where trusted php scripts reside. + * {@link $security} is disabled during their inclusion/execution. + * + * @var array + */ + var $trusted_dir = array(); + + /** + * The left delimiter used for the template tags. + * + * @var string + */ + var $left_delimiter = '{'; + + /** + * The right delimiter used for the template tags. + * + * @var string + */ + var $right_delimiter = '}'; + + /** + * The order in which request variables are registered, similar to + * variables_order in php.ini E = Environment, G = GET, P = POST, + * C = Cookies, S = Server + * + * @var string + */ + var $request_vars_order = 'EGPCS'; + + /** + * Indicates wether $HTTP_*_VARS[] (request_use_auto_globals=false) + * are uses as request-vars or $_*[]-vars. note: if + * request_use_auto_globals is true, then $request_vars_order has + * no effect, but the php-ini-value "gpc_order" + * + * @var boolean + */ + var $request_use_auto_globals = true; + + /** + * Set this if you want different sets of compiled files for the same + * templates. This is useful for things like different languages. + * Instead of creating separate sets of templates per language, you + * set different compile_ids like 'en' and 'de'. + * + * @var string + */ + var $compile_id = null; + + /** + * This tells Smarty whether or not to use sub dirs in the cache/ and + * templates_c/ directories. sub directories better organized, but + * may not work well with PHP safe mode enabled. + * + * @var boolean + * + */ + var $use_sub_dirs = false; + + /** + * This is a list of the modifiers to apply to all template variables. + * Put each modifier in a separate array element in the order you want + * them applied. example: <code>array('escape:"htmlall"');</code> + * + * @var array + */ + var $default_modifiers = array(); + + /** + * This is the resource type to be used when not specified + * at the beginning of the resource path. examples: + * $smarty->display('file:index.tpl'); + * $smarty->display('db:index.tpl'); + * $smarty->display('index.tpl'); // will use default resource type + * {include file="file:index.tpl"} + * {include file="db:index.tpl"} + * {include file="index.tpl"} {* will use default resource type *} + * + * @var array + */ + var $default_resource_type = 'file'; + + /** + * The function used for cache file handling. If not set, built-in caching is used. + * + * @var null|string function name + */ + var $cache_handler_func = null; + + /** + * This indicates which filters are automatically loaded into Smarty. + * + * @var array array of filter names + */ + var $autoload_filters = array(); + + /**#@+ + * @var boolean + */ + /** + * This tells if config file vars of the same name overwrite each other or not. + * if disabled, same name variables are accumulated in an array. + */ + var $config_overwrite = true; + + /** + * This tells whether or not to automatically booleanize config file variables. + * If enabled, then the strings "on", "true", and "yes" are treated as boolean + * true, and "off", "false" and "no" are treated as boolean false. + */ + var $config_booleanize = true; + + /** + * This tells whether hidden sections [.foobar] are readable from the + * tempalates or not. Normally you would never allow this since that is + * the point behind hidden sections: the application can access them, but + * the templates cannot. + */ + var $config_read_hidden = false; + + /** + * This tells whether or not automatically fix newlines in config files. + * It basically converts \r (mac) or \r\n (dos) to \n + */ + var $config_fix_newlines = true; + /**#@-*/ + + /** + * If a template cannot be found, this PHP function will be executed. + * Useful for creating templates on-the-fly or other special action. + * + * @var string function name + */ + var $default_template_handler_func = ''; + + /** + * The file that contains the compiler class. This can a full + * pathname, or relative to the php_include path. + * + * @var string + */ + var $compiler_file = 'Smarty_Compiler.class.php'; + + /** + * The class used for compiling templates. + * + * @var string + */ + var $compiler_class = 'Smarty_Compiler'; + + /** + * The class used to load config vars. + * + * @var string + */ + var $config_class = 'Config_File'; + +/**#@+ + * END Smarty Configuration Section + * There should be no need to touch anything below this line. + * @access private + */ + /** + * where assigned template vars are kept + * + * @var array + */ + var $_tpl_vars = array(); + + /** + * stores run-time $smarty.* vars + * + * @var null|array + */ + var $_smarty_vars = null; + + /** + * keeps track of sections + * + * @var array + */ + var $_sections = array(); + + /** + * keeps track of foreach blocks + * + * @var array + */ + var $_foreach = array(); + + /** + * keeps track of tag hierarchy + * + * @var array + */ + var $_tag_stack = array(); + + /** + * configuration object + * + * @var Config_file + */ + var $_conf_obj = null; + + /** + * loaded configuration settings + * + * @var array + */ + var $_config = array(array('vars' => array(), 'files' => array())); + + /** + * md5 checksum of the string 'Smarty' + * + * @var string + */ + var $_smarty_md5 = 'f8d698aea36fcbead2b9d5359ffca76f'; + + /** + * Smarty version number + * + * @var string + */ + var $_version = '2.6.19'; + + /** + * current template inclusion depth + * + * @var integer + */ + var $_inclusion_depth = 0; + + /** + * for different compiled templates + * + * @var string + */ + var $_compile_id = null; + + /** + * text in URL to enable debug mode + * + * @var string + */ + var $_smarty_debug_id = 'SMARTY_DEBUG'; + + /** + * debugging information for debug console + * + * @var array + */ + var $_smarty_debug_info = array(); + + /** + * info that makes up a cache file + * + * @var array + */ + var $_cache_info = array(); + + /** + * default file permissions + * + * @var integer + */ + var $_file_perms = 0644; + + /** + * default dir permissions + * + * @var integer + */ + var $_dir_perms = 0771; + + /** + * registered objects + * + * @var array + */ + var $_reg_objects = array(); + + /** + * table keeping track of plugins + * + * @var array + */ + var $_plugins = array( + 'modifier' => array(), + 'function' => array(), + 'block' => array(), + 'compiler' => array(), + 'prefilter' => array(), + 'postfilter' => array(), + 'outputfilter' => array(), + 'resource' => array(), + 'insert' => array()); + + + /** + * cache serials + * + * @var array + */ + var $_cache_serials = array(); + + /** + * name of optional cache include file + * + * @var string + */ + var $_cache_include = null; + + /** + * indicate if the current code is used in a compiled + * include + * + * @var string + */ + var $_cache_including = false; + + /**#@-*/ + /** + * The class constructor. + */ + function Smarty() + { + $this->assign('SCRIPT_NAME', isset($_SERVER['SCRIPT_NAME']) ? $_SERVER['SCRIPT_NAME'] + : @$GLOBALS['HTTP_SERVER_VARS']['SCRIPT_NAME']); + } + + /** + * assigns values to template variables + * + * @param array|string $tpl_var the template variable name(s) + * @param mixed $value the value to assign + */ + function assign($tpl_var, $value = null) + { + if (is_array($tpl_var)){ + foreach ($tpl_var as $key => $val) { + if ($key != '') { + $this->_tpl_vars[$key] = $val; + } + } + } else { + if ($tpl_var != '') + $this->_tpl_vars[$tpl_var] = $value; + } + } + + /** + * assigns values to template variables by reference + * + * @param string $tpl_var the template variable name + * @param mixed $value the referenced value to assign + */ + function assign_by_ref($tpl_var, &$value) + { + if ($tpl_var != '') + $this->_tpl_vars[$tpl_var] = &$value; + } + + /** + * appends values to template variables + * + * @param array|string $tpl_var the template variable name(s) + * @param mixed $value the value to append + */ + function append($tpl_var, $value=null, $merge=false) + { + if (is_array($tpl_var)) { + // $tpl_var is an array, ignore $value + foreach ($tpl_var as $_key => $_val) { + if ($_key != '') { + if(!@is_array($this->_tpl_vars[$_key])) { + settype($this->_tpl_vars[$_key],'array'); + } + if($merge && is_array($_val)) { + foreach($_val as $_mkey => $_mval) { + $this->_tpl_vars[$_key][$_mkey] = $_mval; + } + } else { + $this->_tpl_vars[$_key][] = $_val; + } + } + } + } else { + if ($tpl_var != '' && isset($value)) { + if(!@is_array($this->_tpl_vars[$tpl_var])) { + settype($this->_tpl_vars[$tpl_var],'array'); + } + if($merge && is_array($value)) { + foreach($value as $_mkey => $_mval) { + $this->_tpl_vars[$tpl_var][$_mkey] = $_mval; + } + } else { + $this->_tpl_vars[$tpl_var][] = $value; + } + } + } + } + + /** + * appends values to template variables by reference + * + * @param string $tpl_var the template variable name + * @param mixed $value the referenced value to append + */ + function append_by_ref($tpl_var, &$value, $merge=false) + { + if ($tpl_var != '' && isset($value)) { + if(!@is_array($this->_tpl_vars[$tpl_var])) { + settype($this->_tpl_vars[$tpl_var],'array'); + } + if ($merge && is_array($value)) { + foreach($value as $_key => $_val) { + $this->_tpl_vars[$tpl_var][$_key] = &$value[$_key]; + } + } else { + $this->_tpl_vars[$tpl_var][] = &$value; + } + } + } + + + /** + * clear the given assigned template variable. + * + * @param string $tpl_var the template variable to clear + */ + function clear_assign($tpl_var) + { + if (is_array($tpl_var)) + foreach ($tpl_var as $curr_var) + unset($this->_tpl_vars[$curr_var]); + else + unset($this->_tpl_vars[$tpl_var]); + } + + + /** + * Registers custom function to be used in templates + * + * @param string $function the name of the template function + * @param string $function_impl the name of the PHP function to register + */ + function register_function($function, $function_impl, $cacheable=true, $cache_attrs=null) + { + $this->_plugins['function'][$function] = + array($function_impl, null, null, false, $cacheable, $cache_attrs); + + } + + /** + * Unregisters custom function + * + * @param string $function name of template function + */ + function unregister_function($function) + { + unset($this->_plugins['function'][$function]); + } + + /** + * Registers object to be used in templates + * + * @param string $object name of template object + * @param object &$object_impl the referenced PHP object to register + * @param null|array $allowed list of allowed methods (empty = all) + * @param boolean $smarty_args smarty argument format, else traditional + * @param null|array $block_functs list of methods that are block format + */ + function register_object($object, &$object_impl, $allowed = array(), $smarty_args = true, $block_methods = array()) + { + settype($allowed, 'array'); + settype($smarty_args, 'boolean'); + $this->_reg_objects[$object] = + array(&$object_impl, $allowed, $smarty_args, $block_methods); + } + + /** + * Unregisters object + * + * @param string $object name of template object + */ + function unregister_object($object) + { + unset($this->_reg_objects[$object]); + } + + + /** + * Registers block function to be used in templates + * + * @param string $block name of template block + * @param string $block_impl PHP function to register + */ + function register_block($block, $block_impl, $cacheable=true, $cache_attrs=null) + { + $this->_plugins['block'][$block] = + array($block_impl, null, null, false, $cacheable, $cache_attrs); + } + + /** + * Unregisters block function + * + * @param string $block name of template function + */ + function unregister_block($block) + { + unset($this->_plugins['block'][$block]); + } + + /** + * Registers compiler function + * + * @param string $function name of template function + * @param string $function_impl name of PHP function to register + */ + function register_compiler_function($function, $function_impl, $cacheable=true) + { + $this->_plugins['compiler'][$function] = + array($function_impl, null, null, false, $cacheable); + } + + /** + * Unregisters compiler function + * + * @param string $function name of template function + */ + function unregister_compiler_function($function) + { + unset($this->_plugins['compiler'][$function]); + } + + /** + * Registers modifier to be used in templates + * + * @param string $modifier name of template modifier + * @param string $modifier_impl name of PHP function to register + */ + function register_modifier($modifier, $modifier_impl) + { + $this->_plugins['modifier'][$modifier] = + array($modifier_impl, null, null, false); + } + + /** + * Unregisters modifier + * + * @param string $modifier name of template modifier + */ + function unregister_modifier($modifier) + { + unset($this->_plugins['modifier'][$modifier]); + } + + /** + * Registers a resource to fetch a template + * + * @param string $type name of resource + * @param array $functions array of functions to handle resource + */ + function register_resource($type, $functions) + { + if (count($functions)==4) { + $this->_plugins['resource'][$type] = + array($functions, false); + + } elseif (count($functions)==5) { + $this->_plugins['resource'][$type] = + array(array(array(&$functions[0], $functions[1]) + ,array(&$functions[0], $functions[2]) + ,array(&$functions[0], $functions[3]) + ,array(&$functions[0], $functions[4])) + ,false); + + } else { + $this->trigger_error("malformed function-list for '$type' in register_resource"); + + } + } + + /** + * Unregisters a resource + * + * @param string $type name of resource + */ + function unregister_resource($type) + { + unset($this->_plugins['resource'][$type]); + } + + /** + * Registers a prefilter function to apply + * to a template before compiling + * + * @param callback $function + */ + function register_prefilter($function) + { + $this->_plugins['prefilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters a prefilter function + * + * @param callback $function + */ + function unregister_prefilter($function) + { + unset($this->_plugins['prefilter'][$this->_get_filter_name($function)]); + } + + /** + * Registers a postfilter function to apply + * to a compiled template after compilation + * + * @param callback $function + */ + function register_postfilter($function) + { + $this->_plugins['postfilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters a postfilter function + * + * @param callback $function + */ + function unregister_postfilter($function) + { + unset($this->_plugins['postfilter'][$this->_get_filter_name($function)]); + } + + /** + * Registers an output filter function to apply + * to a template output + * + * @param callback $function + */ + function register_outputfilter($function) + { + $this->_plugins['outputfilter'][$this->_get_filter_name($function)] + = array($function, null, null, false); + } + + /** + * Unregisters an outputfilter function + * + * @param callback $function + */ + function unregister_outputfilter($function) + { + unset($this->_plugins['outputfilter'][$this->_get_filter_name($function)]); + } + + /** + * load a filter of specified type and name + * + * @param string $type filter type + * @param string $name filter name + */ + function load_filter($type, $name) + { + switch ($type) { + case 'output': + $_params = array('plugins' => array(array($type . 'filter', $name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + break; + + case 'pre': + case 'post': + if (!isset($this->_plugins[$type . 'filter'][$name])) + $this->_plugins[$type . 'filter'][$name] = false; + break; + } + } + + /** + * clear cached content for the given template and cache id + * + * @param string $tpl_file name of template file + * @param string $cache_id name of cache_id + * @param string $compile_id name of compile_id + * @param string $exp_time expiration time + * @return boolean + */ + function clear_cache($tpl_file = null, $cache_id = null, $compile_id = null, $exp_time = null) + { + + if (!isset($compile_id)) + $compile_id = $this->compile_id; + + if (!isset($tpl_file)) + $compile_id = null; + + $_auto_id = $this->_get_auto_id($cache_id, $compile_id); + + if (!empty($this->cache_handler_func)) { + return call_user_func_array($this->cache_handler_func, + array('clear', &$this, &$dummy, $tpl_file, $cache_id, $compile_id, $exp_time)); + } else { + $_params = array('auto_base' => $this->cache_dir, + 'auto_source' => $tpl_file, + 'auto_id' => $_auto_id, + 'exp_time' => $exp_time); + require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + + } + + + /** + * clear the entire contents of cache (all templates) + * + * @param string $exp_time expire time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + function clear_all_cache($exp_time = null) + { + return $this->clear_cache(null, null, null, $exp_time); + } + + + /** + * test to see if valid cache exists for this template + * + * @param string $tpl_file name of template file + * @param string $cache_id + * @param string $compile_id + * @return string|false results of {@link _read_cache_file()} + */ + function is_cached($tpl_file, $cache_id = null, $compile_id = null) + { + if (!$this->caching) + return false; + + if (!isset($compile_id)) + $compile_id = $this->compile_id; + + $_params = array( + 'tpl_file' => $tpl_file, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id + ); + require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); + return smarty_core_read_cache_file($_params, $this); + } + + + /** + * clear all the assigned template variables. + * + */ + function clear_all_assign() + { + $this->_tpl_vars = array(); + } + + /** + * clears compiled version of specified template resource, + * or all compiled template files if one is not specified. + * This function is for advanced use only, not normally needed. + * + * @param string $tpl_file + * @param string $compile_id + * @param string $exp_time + * @return boolean results of {@link smarty_core_rm_auto()} + */ + function clear_compiled_tpl($tpl_file = null, $compile_id = null, $exp_time = null) + { + if (!isset($compile_id)) { + $compile_id = $this->compile_id; + } + $_params = array('auto_base' => $this->compile_dir, + 'auto_source' => $tpl_file, + 'auto_id' => $compile_id, + 'exp_time' => $exp_time, + 'extensions' => array('.inc', '.php')); + require_once(SMARTY_CORE_DIR . 'core.rm_auto.php'); + return smarty_core_rm_auto($_params, $this); + } + + /** + * Checks whether requested template exists. + * + * @param string $tpl_file + * @return boolean + */ + function template_exists($tpl_file) + { + $_params = array('resource_name' => $tpl_file, 'quiet'=>true, 'get_source'=>false); + return $this->_fetch_resource_info($_params); + } + + /** + * Returns an array containing template variables + * + * @param string $name + * @param string $type + * @return array + */ + function &get_template_vars($name=null) + { + if(!isset($name)) { + return $this->_tpl_vars; + } elseif(isset($this->_tpl_vars[$name])) { + return $this->_tpl_vars[$name]; + } else { + // var non-existant, return valid reference + $_tmp = null; + return $_tmp; + } + } + + /** + * Returns an array containing config variables + * + * @param string $name + * @param string $type + * @return array + */ + function &get_config_vars($name=null) + { + if(!isset($name) && is_array($this->_config[0])) { + return $this->_config[0]['vars']; + } else if(isset($this->_config[0]['vars'][$name])) { + return $this->_config[0]['vars'][$name]; + } else { + // var non-existant, return valid reference + $_tmp = null; + return $_tmp; + } + } + + /** + * trigger Smarty error + * + * @param string $error_msg + * @param integer $error_type + */ + function trigger_error($error_msg, $error_type = E_USER_WARNING) + { + trigger_error("Smarty error: $error_msg", $error_type); + } + + + /** + * executes & displays the template results + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + */ + function display($resource_name, $cache_id = null, $compile_id = null) + { + $this->fetch($resource_name, $cache_id, $compile_id, true); + } + + /** + * executes & returns or displays the template results + * + * @param string $resource_name + * @param string $cache_id + * @param string $compile_id + * @param boolean $display + */ + function fetch($resource_name, $cache_id = null, $compile_id = null, $display = false) + { + static $_cache_info = array(); + + $_smarty_old_error_level = $this->debugging ? error_reporting() : error_reporting(isset($this->error_reporting) + ? $this->error_reporting : error_reporting() & ~E_NOTICE); + + if (!$this->debugging && $this->debugging_ctrl == 'URL') { + $_query_string = $this->request_use_auto_globals ? $_SERVER['QUERY_STRING'] : $GLOBALS['HTTP_SERVER_VARS']['QUERY_STRING']; + if (@strstr($_query_string, $this->_smarty_debug_id)) { + if (@strstr($_query_string, $this->_smarty_debug_id . '=on')) { + // enable debugging for this browser session + @setcookie('SMARTY_DEBUG', true); + $this->debugging = true; + } elseif (@strstr($_query_string, $this->_smarty_debug_id . '=off')) { + // disable debugging for this browser session + @setcookie('SMARTY_DEBUG', false); + $this->debugging = false; + } else { + // enable debugging for this page + $this->debugging = true; + } + } else { + $this->debugging = (bool)($this->request_use_auto_globals ? @$_COOKIE['SMARTY_DEBUG'] : @$GLOBALS['HTTP_COOKIE_VARS']['SMARTY_DEBUG']); + } + } + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $_debug_start_time = smarty_core_get_microtime($_params, $this); + $this->_smarty_debug_info[] = array('type' => 'template', + 'filename' => $resource_name, + 'depth' => 0); + $_included_tpls_idx = count($this->_smarty_debug_info) - 1; + } + + if (!isset($compile_id)) { + $compile_id = $this->compile_id; + } + + $this->_compile_id = $compile_id; + $this->_inclusion_depth = 0; + + if ($this->caching) { + // save old cache_info, initialize cache_info + array_push($_cache_info, $this->_cache_info); + $this->_cache_info = array(); + $_params = array( + 'tpl_file' => $resource_name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'results' => null + ); + require_once(SMARTY_CORE_DIR . 'core.read_cache_file.php'); + if (smarty_core_read_cache_file($_params, $this)) { + $_smarty_results = $_params['results']; + if (!empty($this->_cache_info['insert_tags'])) { + $_params = array('plugins' => $this->_cache_info['insert_tags']); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + $_params = array('results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); + $_smarty_results = smarty_core_process_cached_inserts($_params, $this); + } + if (!empty($this->_cache_info['cache_serials'])) { + $_params = array('results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.process_compiled_include.php'); + $_smarty_results = smarty_core_process_compiled_include($_params, $this); + } + + + if ($display) { + if ($this->debugging) + { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $_debug_start_time; + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + $_smarty_results .= smarty_core_display_debug_console($_params, $this); + } + if ($this->cache_modified_check) { + $_server_vars = ($this->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; + $_last_modified_date = @substr($_server_vars['HTTP_IF_MODIFIED_SINCE'], 0, strpos($_server_vars['HTTP_IF_MODIFIED_SINCE'], 'GMT') + 3); + $_gmt_mtime = gmdate('D, d M Y H:i:s', $this->_cache_info['timestamp']).' GMT'; + if (@count($this->_cache_info['insert_tags']) == 0 + && !$this->_cache_serials + && $_gmt_mtime == $_last_modified_date) { + if (php_sapi_name()=='cgi') + header('Status: 304 Not Modified'); + else + header('HTTP/1.1 304 Not Modified'); + + } else { + header('Last-Modified: '.$_gmt_mtime); + echo $_smarty_results; + } + } else { + echo $_smarty_results; + } + error_reporting($_smarty_old_error_level); + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + return true; + } else { + error_reporting($_smarty_old_error_level); + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + return $_smarty_results; + } + } else { + $this->_cache_info['template'][$resource_name] = true; + if ($this->cache_modified_check && $display) { + header('Last-Modified: '.gmdate('D, d M Y H:i:s', time()).' GMT'); + } + } + } + + // load filters that are marked as autoload + if (count($this->autoload_filters)) { + foreach ($this->autoload_filters as $_filter_type => $_filters) { + foreach ($_filters as $_filter) { + $this->load_filter($_filter_type, $_filter); + } + } + } + + $_smarty_compile_path = $this->_get_compile_path($resource_name); + + // if we just need to display the results, don't perform output + // buffering - for speed + $_cache_including = $this->_cache_including; + $this->_cache_including = false; + if ($display && !$this->caching && count($this->_plugins['outputfilter']) == 0) { + if ($this->_is_compiled($resource_name, $_smarty_compile_path) + || $this->_compile_resource($resource_name, $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + } else { + ob_start(); + if ($this->_is_compiled($resource_name, $_smarty_compile_path) + || $this->_compile_resource($resource_name, $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + $_smarty_results = ob_get_contents(); + ob_end_clean(); + + foreach ((array)$this->_plugins['outputfilter'] as $_output_filter) { + $_smarty_results = call_user_func_array($_output_filter[0], array($_smarty_results, &$this)); + } + } + + if ($this->caching) { + $_params = array('tpl_file' => $resource_name, + 'cache_id' => $cache_id, + 'compile_id' => $compile_id, + 'results' => $_smarty_results); + require_once(SMARTY_CORE_DIR . 'core.write_cache_file.php'); + smarty_core_write_cache_file($_params, $this); + require_once(SMARTY_CORE_DIR . 'core.process_cached_inserts.php'); + $_smarty_results = smarty_core_process_cached_inserts($_params, $this); + + if ($this->_cache_serials) { + // strip nocache-tags from output + $_smarty_results = preg_replace('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!s' + ,'' + ,$_smarty_results); + } + // restore initial cache_info + $this->_cache_info = array_pop($_cache_info); + } + $this->_cache_including = $_cache_including; + + if ($display) { + if (isset($_smarty_results)) { echo $_smarty_results; } + } + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$_included_tpls_idx]['exec_time'] = (smarty_core_get_microtime($_params, $this) - $_debug_start_time); + } + + if ($display) { + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + echo smarty_core_display_debug_console($_params, $this); + } + error_reporting($_smarty_old_error_level); + return; + } else { + error_reporting($_smarty_old_error_level); + if (isset($_smarty_results)) { return $_smarty_results; } + } + } + + /** + * load configuration values + * + * @param string $file + * @param string $section + * @param string $scope + */ + function config_load($file, $section = null, $scope = 'global') + { + require_once($this->_get_plugin_filepath('function', 'config_load')); + smarty_function_config_load(array('file' => $file, 'section' => $section, 'scope' => $scope), $this); + } + + /** + * return a reference to a registered object + * + * @param string $name + * @return object + */ + function &get_registered_object($name) { + if (!isset($this->_reg_objects[$name])) + $this->_trigger_fatal_error("'$name' is not a registered object"); + + if (!is_object($this->_reg_objects[$name][0])) + $this->_trigger_fatal_error("registered '$name' is not an object"); + + return $this->_reg_objects[$name][0]; + } + + /** + * clear configuration values + * + * @param string $var + */ + function clear_config($var = null) + { + if(!isset($var)) { + // clear all values + $this->_config = array(array('vars' => array(), + 'files' => array())); + } else { + unset($this->_config[0]['vars'][$var]); + } + } + + /** + * get filepath of requested plugin + * + * @param string $type + * @param string $name + * @return string|false + */ + function _get_plugin_filepath($type, $name) + { + $_params = array('type' => $type, 'name' => $name); + require_once(SMARTY_CORE_DIR . 'core.assemble_plugin_filepath.php'); + return smarty_core_assemble_plugin_filepath($_params, $this); + } + + /** + * test if resource needs compiling + * + * @param string $resource_name + * @param string $compile_path + * @return boolean + */ + function _is_compiled($resource_name, $compile_path) + { + if (!$this->force_compile && file_exists($compile_path)) { + if (!$this->compile_check) { + // no need to check compiled file + return true; + } else { + // get file source and timestamp + $_params = array('resource_name' => $resource_name, 'get_source'=>false); + if (!$this->_fetch_resource_info($_params)) { + return false; + } + if ($_params['resource_timestamp'] <= filemtime($compile_path)) { + // template not expired, no recompile + return true; + } else { + // compile template + return false; + } + } + } else { + // compiled template does not exist, or forced compile + return false; + } + } + + /** + * compile the template + * + * @param string $resource_name + * @param string $compile_path + * @return boolean + */ + function _compile_resource($resource_name, $compile_path) + { + + $_params = array('resource_name' => $resource_name); + if (!$this->_fetch_resource_info($_params)) { + return false; + } + + $_source_content = $_params['source_content']; + $_cache_include = substr($compile_path, 0, -4).'.inc'; + + if ($this->_compile_source($resource_name, $_source_content, $_compiled_content, $_cache_include)) { + // if a _cache_serial was set, we also have to write an include-file: + if ($this->_cache_include_info) { + require_once(SMARTY_CORE_DIR . 'core.write_compiled_include.php'); + smarty_core_write_compiled_include(array_merge($this->_cache_include_info, array('compiled_content'=>$_compiled_content, 'resource_name'=>$resource_name)), $this); + } + + $_params = array('compile_path'=>$compile_path, 'compiled_content' => $_compiled_content); + require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); + smarty_core_write_compiled_resource($_params, $this); + + return true; + } else { + return false; + } + + } + + /** + * compile the given source + * + * @param string $resource_name + * @param string $source_content + * @param string $compiled_content + * @return boolean + */ + function _compile_source($resource_name, &$source_content, &$compiled_content, $cache_include_path=null) + { + if (file_exists(SMARTY_DIR . $this->compiler_file)) { + require_once(SMARTY_DIR . $this->compiler_file); + } else { + // use include_path + require_once($this->compiler_file); + } + + + $smarty_compiler = new $this->compiler_class; + + $smarty_compiler->template_dir = $this->template_dir; + $smarty_compiler->compile_dir = $this->compile_dir; + $smarty_compiler->plugins_dir = $this->plugins_dir; + $smarty_compiler->config_dir = $this->config_dir; + $smarty_compiler->force_compile = $this->force_compile; + $smarty_compiler->caching = $this->caching; + $smarty_compiler->php_handling = $this->php_handling; + $smarty_compiler->left_delimiter = $this->left_delimiter; + $smarty_compiler->right_delimiter = $this->right_delimiter; + $smarty_compiler->_version = $this->_version; + $smarty_compiler->security = $this->security; + $smarty_compiler->secure_dir = $this->secure_dir; + $smarty_compiler->security_settings = $this->security_settings; + $smarty_compiler->trusted_dir = $this->trusted_dir; + $smarty_compiler->use_sub_dirs = $this->use_sub_dirs; + $smarty_compiler->_reg_objects = &$this->_reg_objects; + $smarty_compiler->_plugins = &$this->_plugins; + $smarty_compiler->_tpl_vars = &$this->_tpl_vars; + $smarty_compiler->default_modifiers = $this->default_modifiers; + $smarty_compiler->compile_id = $this->_compile_id; + $smarty_compiler->_config = $this->_config; + $smarty_compiler->request_use_auto_globals = $this->request_use_auto_globals; + + if (isset($cache_include_path) && isset($this->_cache_serials[$cache_include_path])) { + $smarty_compiler->_cache_serial = $this->_cache_serials[$cache_include_path]; + } + $smarty_compiler->_cache_include = $cache_include_path; + + + $_results = $smarty_compiler->_compile_file($resource_name, $source_content, $compiled_content); + + if ($smarty_compiler->_cache_serial) { + $this->_cache_include_info = array( + 'cache_serial'=>$smarty_compiler->_cache_serial + ,'plugins_code'=>$smarty_compiler->_plugins_code + ,'include_file_path' => $cache_include_path); + + } else { + $this->_cache_include_info = null; + + } + + return $_results; + } + + /** + * Get the compile path for this resource + * + * @param string $resource_name + * @return string results of {@link _get_auto_filename()} + */ + function _get_compile_path($resource_name) + { + return $this->_get_auto_filename($this->compile_dir, $resource_name, + $this->_compile_id) . '.php'; + } + + /** + * fetch the template info. Gets timestamp, and source + * if get_source is true + * + * sets $source_content to the source of the template, and + * $resource_timestamp to its time stamp + * @param string $resource_name + * @param string $source_content + * @param integer $resource_timestamp + * @param boolean $get_source + * @param boolean $quiet + * @return boolean + */ + + function _fetch_resource_info(&$params) + { + if(!isset($params['get_source'])) { $params['get_source'] = true; } + if(!isset($params['quiet'])) { $params['quiet'] = false; } + + $_return = false; + $_params = array('resource_name' => $params['resource_name']) ; + if (isset($params['resource_base_path'])) + $_params['resource_base_path'] = $params['resource_base_path']; + else + $_params['resource_base_path'] = $this->template_dir; + + if ($this->_parse_resource_name($_params)) { + $_resource_type = $_params['resource_type']; + $_resource_name = $_params['resource_name']; + switch ($_resource_type) { + case 'file': + if ($params['get_source']) { + $params['source_content'] = $this->_read_file($_resource_name); + } + $params['resource_timestamp'] = filemtime($_resource_name); + $_return = is_file($_resource_name); + break; + + default: + // call resource functions to fetch the template source and timestamp + if ($params['get_source']) { + $_source_return = isset($this->_plugins['resource'][$_resource_type]) && + call_user_func_array($this->_plugins['resource'][$_resource_type][0][0], + array($_resource_name, &$params['source_content'], &$this)); + } else { + $_source_return = true; + } + + $_timestamp_return = isset($this->_plugins['resource'][$_resource_type]) && + call_user_func_array($this->_plugins['resource'][$_resource_type][0][1], + array($_resource_name, &$params['resource_timestamp'], &$this)); + + $_return = $_source_return && $_timestamp_return; + break; + } + } + + if (!$_return) { + // see if we can get a template with the default template handler + if (!empty($this->default_template_handler_func)) { + if (!is_callable($this->default_template_handler_func)) { + $this->trigger_error("default template handler function \"$this->default_template_handler_func\" doesn't exist."); + } else { + $_return = call_user_func_array( + $this->default_template_handler_func, + array($_params['resource_type'], $_params['resource_name'], &$params['source_content'], &$params['resource_timestamp'], &$this)); + } + } + } + + if (!$_return) { + if (!$params['quiet']) { + $this->trigger_error('unable to read resource: "' . $params['resource_name'] . '"'); + } + } else if ($_return && $this->security) { + require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); + if (!smarty_core_is_secure($_params, $this)) { + if (!$params['quiet']) + $this->trigger_error('(secure mode) accessing "' . $params['resource_name'] . '" is not allowed'); + $params['source_content'] = null; + $params['resource_timestamp'] = null; + return false; + } + } + return $_return; + } + + + /** + * parse out the type and name from the resource + * + * @param string $resource_base_path + * @param string $resource_name + * @param string $resource_type + * @param string $resource_name + * @return boolean + */ + + function _parse_resource_name(&$params) + { + + // split tpl_path by the first colon + $_resource_name_parts = explode(':', $params['resource_name'], 2); + + if (count($_resource_name_parts) == 1) { + // no resource type given + $params['resource_type'] = $this->default_resource_type; + $params['resource_name'] = $_resource_name_parts[0]; + } else { + if(strlen($_resource_name_parts[0]) == 1) { + // 1 char is not resource type, but part of filepath + $params['resource_type'] = $this->default_resource_type; + $params['resource_name'] = $params['resource_name']; + } else { + $params['resource_type'] = $_resource_name_parts[0]; + $params['resource_name'] = $_resource_name_parts[1]; + } + } + + if ($params['resource_type'] == 'file') { + if (!preg_match('/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/', $params['resource_name'])) { + // relative pathname to $params['resource_base_path'] + // use the first directory where the file is found + foreach ((array)$params['resource_base_path'] as $_curr_path) { + $_fullpath = $_curr_path . DIRECTORY_SEPARATOR . $params['resource_name']; + if (file_exists($_fullpath) && is_file($_fullpath)) { + $params['resource_name'] = $_fullpath; + return true; + } + // didn't find the file, try include_path + $_params = array('file_path' => $_fullpath); + require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $this)) { + $params['resource_name'] = $_params['new_file_path']; + return true; + } + } + return false; + } else { + /* absolute path */ + return file_exists($params['resource_name']); + } + } elseif (empty($this->_plugins['resource'][$params['resource_type']])) { + $_params = array('type' => $params['resource_type']); + require_once(SMARTY_CORE_DIR . 'core.load_resource_plugin.php'); + smarty_core_load_resource_plugin($_params, $this); + } + + return true; + } + + + /** + * Handle modifiers + * + * @param string|null $modifier_name + * @param array|null $map_array + * @return string result of modifiers + */ + function _run_mod_handler() + { + $_args = func_get_args(); + list($_modifier_name, $_map_array) = array_splice($_args, 0, 2); + list($_func_name, $_tpl_file, $_tpl_line) = + $this->_plugins['modifier'][$_modifier_name]; + + $_var = $_args[0]; + foreach ($_var as $_key => $_val) { + $_args[0] = $_val; + $_var[$_key] = call_user_func_array($_func_name, $_args); + } + return $_var; + } + + /** + * Remove starting and ending quotes from the string + * + * @param string $string + * @return string + */ + function _dequote($string) + { + if ((substr($string, 0, 1) == "'" || substr($string, 0, 1) == '"') && + substr($string, -1) == substr($string, 0, 1)) + return substr($string, 1, -1); + else + return $string; + } + + + /** + * read in a file + * + * @param string $filename + * @return string + */ + function _read_file($filename) + { + if ( file_exists($filename) && ($fd = @fopen($filename, 'rb')) ) { + $contents = ''; + while (!feof($fd)) { + $contents .= fread($fd, 8192); + } + fclose($fd); + return $contents; + } else { + return false; + } + } + + /** + * get a concrete filename for automagically created content + * + * @param string $auto_base + * @param string $auto_source + * @param string $auto_id + * @return string + * @staticvar string|null + * @staticvar string|null + */ + function _get_auto_filename($auto_base, $auto_source = null, $auto_id = null) + { + $_compile_dir_sep = $this->use_sub_dirs ? DIRECTORY_SEPARATOR : '^'; + $_return = $auto_base . DIRECTORY_SEPARATOR; + + if(isset($auto_id)) { + // make auto_id safe for directory names + $auto_id = str_replace('%7C',$_compile_dir_sep,(urlencode($auto_id))); + // split into separate directories + $_return .= $auto_id . $_compile_dir_sep; + } + + if(isset($auto_source)) { + // make source name safe for filename + $_filename = urlencode(basename($auto_source)); + $_crc32 = sprintf('%08X', crc32($auto_source)); + // prepend %% to avoid name conflicts with + // with $params['auto_id'] names + $_crc32 = substr($_crc32, 0, 2) . $_compile_dir_sep . + substr($_crc32, 0, 3) . $_compile_dir_sep . $_crc32; + $_return .= '%%' . $_crc32 . '%%' . $_filename; + } + + return $_return; + } + + /** + * unlink a file, possibly using expiration time + * + * @param string $resource + * @param integer $exp_time + */ + function _unlink($resource, $exp_time = null) + { + if(isset($exp_time)) { + if(time() - @filemtime($resource) >= $exp_time) { + return @unlink($resource); + } + } else { + return @unlink($resource); + } + } + + /** + * returns an auto_id for auto-file-functions + * + * @param string $cache_id + * @param string $compile_id + * @return string|null + */ + function _get_auto_id($cache_id=null, $compile_id=null) { + if (isset($cache_id)) + return (isset($compile_id)) ? $cache_id . '|' . $compile_id : $cache_id; + elseif(isset($compile_id)) + return $compile_id; + else + return null; + } + + /** + * trigger Smarty plugin error + * + * @param string $error_msg + * @param string $tpl_file + * @param integer $tpl_line + * @param string $file + * @param integer $line + * @param integer $error_type + */ + function _trigger_fatal_error($error_msg, $tpl_file = null, $tpl_line = null, + $file = null, $line = null, $error_type = E_USER_ERROR) + { + if(isset($file) && isset($line)) { + $info = ' ('.basename($file).", line $line)"; + } else { + $info = ''; + } + if (isset($tpl_line) && isset($tpl_file)) { + $this->trigger_error('[in ' . $tpl_file . ' line ' . $tpl_line . "]: $error_msg$info", $error_type); + } else { + $this->trigger_error($error_msg . $info, $error_type); + } + } + + + /** + * callback function for preg_replace, to call a non-cacheable block + * @return string + */ + function _process_compiled_include_callback($match) { + $_func = '_smarty_tplfunc_'.$match[2].'_'.$match[3]; + ob_start(); + $_func($this); + $_ret = ob_get_contents(); + ob_end_clean(); + return $_ret; + } + + + /** + * called for included templates + * + * @param string $_smarty_include_tpl_file + * @param string $_smarty_include_vars + */ + + // $_smarty_include_tpl_file, $_smarty_include_vars + + function _smarty_include($params) + { + if ($this->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $debug_start_time = smarty_core_get_microtime($_params, $this); + $this->_smarty_debug_info[] = array('type' => 'template', + 'filename' => $params['smarty_include_tpl_file'], + 'depth' => ++$this->_inclusion_depth); + $included_tpls_idx = count($this->_smarty_debug_info) - 1; + } + + $this->_tpl_vars = array_merge($this->_tpl_vars, $params['smarty_include_vars']); + + // config vars are treated as local, so push a copy of the + // current ones onto the front of the stack + array_unshift($this->_config, $this->_config[0]); + + $_smarty_compile_path = $this->_get_compile_path($params['smarty_include_tpl_file']); + + + if ($this->_is_compiled($params['smarty_include_tpl_file'], $_smarty_compile_path) + || $this->_compile_resource($params['smarty_include_tpl_file'], $_smarty_compile_path)) + { + include($_smarty_compile_path); + } + + // pop the local vars off the front of the stack + array_shift($this->_config); + + $this->_inclusion_depth--; + + if ($this->debugging) { + // capture time for debugging info + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $this->_smarty_debug_info[$included_tpls_idx]['exec_time'] = smarty_core_get_microtime($_params, $this) - $debug_start_time; + } + + if ($this->caching) { + $this->_cache_info['template'][$params['smarty_include_tpl_file']] = true; + } + } + + + /** + * get or set an array of cached attributes for function that is + * not cacheable + * @return array + */ + function &_smarty_cache_attrs($cache_serial, $count) { + $_cache_attrs =& $this->_cache_info['cache_attrs'][$cache_serial][$count]; + + if ($this->_cache_including) { + /* return next set of cache_attrs */ + $_return = current($_cache_attrs); + next($_cache_attrs); + return $_return; + + } else { + /* add a reference to a new set of cache_attrs */ + $_cache_attrs[] = array(); + return $_cache_attrs[count($_cache_attrs)-1]; + + } + + } + + + /** + * wrapper for include() retaining $this + * @return mixed + */ + function _include($filename, $once=false, $params=null) + { + if ($once) { + return include_once($filename); + } else { + return include($filename); + } + } + + + /** + * wrapper for eval() retaining $this + * @return mixed + */ + function _eval($code, $params=null) + { + return eval($code); + } + + /** + * Extracts the filter name from the given callback + * + * @param callback $function + * @return string + */ + function _get_filter_name($function) + { + if (is_array($function)) { + $_class_name = (is_object($function[0]) ? + get_class($function[0]) : $function[0]); + return $_class_name . '_' . $function[1]; + } + else { + return $function; + } + } + + /**#@-*/ + +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/Smarty_Compiler.class.php b/BSF/include/smarty/libs/Smarty_Compiler.class.php new file mode 100644 index 000000000..d5f877f7b --- /dev/null +++ b/BSF/include/smarty/libs/Smarty_Compiler.class.php @@ -0,0 +1,2325 @@ +<?php + +/** + * Project: Smarty: the PHP compiling template engine + * File: Smarty_Compiler.class.php + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * @link http://smarty.php.net/ + * @author Monte Ohrt <monte at ohrt dot com> + * @author Andrei Zmievski <andrei@php.net> + * @version 2.6.19 + * @copyright 2001-2005 New Digital Group, Inc. + * @package Smarty + */ + +/* $Id$ */ + +/** + * Template compiling class + * @package Smarty + */ +class Smarty_Compiler extends Smarty { + + // internal vars + /**#@+ + * @access private + */ + var $_folded_blocks = array(); // keeps folded template blocks + var $_current_file = null; // the current template being compiled + var $_current_line_no = 1; // line number for error messages + var $_capture_stack = array(); // keeps track of nested capture buffers + var $_plugin_info = array(); // keeps track of plugins to load + var $_init_smarty_vars = false; + var $_permitted_tokens = array('true','false','yes','no','on','off','null'); + var $_db_qstr_regexp = null; // regexps are setup in the constructor + var $_si_qstr_regexp = null; + var $_qstr_regexp = null; + var $_func_regexp = null; + var $_reg_obj_regexp = null; + var $_var_bracket_regexp = null; + var $_num_const_regexp = null; + var $_dvar_guts_regexp = null; + var $_dvar_regexp = null; + var $_cvar_regexp = null; + var $_svar_regexp = null; + var $_avar_regexp = null; + var $_mod_regexp = null; + var $_var_regexp = null; + var $_parenth_param_regexp = null; + var $_func_call_regexp = null; + var $_obj_ext_regexp = null; + var $_obj_start_regexp = null; + var $_obj_params_regexp = null; + var $_obj_call_regexp = null; + var $_cacheable_state = 0; + var $_cache_attrs_count = 0; + var $_nocache_count = 0; + var $_cache_serial = null; + var $_cache_include = null; + + var $_strip_depth = 0; + var $_additional_newline = "\n"; + + /**#@-*/ + /** + * The class constructor. + */ + function Smarty_Compiler() + { + // matches double quoted strings: + // "foobar" + // "foo\"bar" + $this->_db_qstr_regexp = '"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'; + + // matches single quoted strings: + // 'foobar' + // 'foo\'bar' + $this->_si_qstr_regexp = '\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''; + + // matches single or double quoted strings + $this->_qstr_regexp = '(?:' . $this->_db_qstr_regexp . '|' . $this->_si_qstr_regexp . ')'; + + // matches bracket portion of vars + // [0] + // [foo] + // [$bar] + $this->_var_bracket_regexp = '\[\$?[\w\.]+\]'; + + // matches numerical constants + // 30 + // -12 + // 13.22 + $this->_num_const_regexp = '(?:\-?\d+(?:\.\d+)?)'; + + // matches $ vars (not objects): + // $foo + // $foo.bar + // $foo.bar.foobar + // $foo[0] + // $foo[$bar] + // $foo[5][blah] + // $foo[5].bar[$foobar][4] + $this->_dvar_math_regexp = '(?:[\+\*\/\%]|(?:-(?!>)))'; + $this->_dvar_math_var_regexp = '[\$\w\.\+\-\*\/\%\d\>\[\]]'; + $this->_dvar_guts_regexp = '\w+(?:' . $this->_var_bracket_regexp + . ')*(?:\.\$?\w+(?:' . $this->_var_bracket_regexp . ')*)*(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?'; + $this->_dvar_regexp = '\$' . $this->_dvar_guts_regexp; + + // matches config vars: + // #foo# + // #foobar123_foo# + $this->_cvar_regexp = '\#\w+\#'; + + // matches section vars: + // %foo.bar% + $this->_svar_regexp = '\%\w+\.\w+\%'; + + // matches all valid variables (no quotes, no modifiers) + $this->_avar_regexp = '(?:' . $this->_dvar_regexp . '|' + . $this->_cvar_regexp . '|' . $this->_svar_regexp . ')'; + + // matches valid variable syntax: + // $foo + // $foo + // #foo# + // #foo# + // "text" + // "text" + $this->_var_regexp = '(?:' . $this->_avar_regexp . '|' . $this->_qstr_regexp . ')'; + + // matches valid object call (one level of object nesting allowed in parameters): + // $foo->bar + // $foo->bar() + // $foo->bar("text") + // $foo->bar($foo, $bar, "text") + // $foo->bar($foo, "foo") + // $foo->bar->foo() + // $foo->bar->foo->bar() + // $foo->bar($foo->bar) + // $foo->bar($foo->bar()) + // $foo->bar($foo->bar($blah,$foo,44,"foo",$foo[0].bar)) + $this->_obj_ext_regexp = '\->(?:\$?' . $this->_dvar_guts_regexp . ')'; + $this->_obj_restricted_param_regexp = '(?:' + . '(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')(?:' . $this->_obj_ext_regexp . '(?:\((?:(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . ')' + . '(?:\s*,\s*(?:' . $this->_var_regexp . '|' . $this->_num_const_regexp . '))*)?\))?)*)'; + $this->_obj_single_param_regexp = '(?:\w+|' . $this->_obj_restricted_param_regexp . '(?:\s*,\s*(?:(?:\w+|' + . $this->_var_regexp . $this->_obj_restricted_param_regexp . ')))*)'; + $this->_obj_params_regexp = '\((?:' . $this->_obj_single_param_regexp + . '(?:\s*,\s*' . $this->_obj_single_param_regexp . ')*)?\)'; + $this->_obj_start_regexp = '(?:' . $this->_dvar_regexp . '(?:' . $this->_obj_ext_regexp . ')+)'; + $this->_obj_call_regexp = '(?:' . $this->_obj_start_regexp . '(?:' . $this->_obj_params_regexp . ')?(?:' . $this->_dvar_math_regexp . '(?:' . $this->_num_const_regexp . '|' . $this->_dvar_math_var_regexp . ')*)?)'; + + // matches valid modifier syntax: + // |foo + // |@foo + // |foo:"bar" + // |foo:$bar + // |foo:"bar":$foobar + // |foo|bar + // |foo:$foo->bar + $this->_mod_regexp = '(?:\|@?\w+(?::(?:\w+|' . $this->_num_const_regexp . '|' + . $this->_obj_call_regexp . '|' . $this->_avar_regexp . '|' . $this->_qstr_regexp .'))*)'; + + // matches valid function name: + // foo123 + // _foo_bar + $this->_func_regexp = '[a-zA-Z_]\w*'; + + // matches valid registered object: + // foo->bar + $this->_reg_obj_regexp = '[a-zA-Z_]\w*->[a-zA-Z_]\w*'; + + // matches valid parameter values: + // true + // $foo + // $foo|bar + // #foo# + // #foo#|bar + // "text" + // "text"|bar + // $foo->bar + $this->_param_regexp = '(?:\s*(?:' . $this->_obj_call_regexp . '|' + . $this->_var_regexp . '|' . $this->_num_const_regexp . '|\w+)(?>' . $this->_mod_regexp . '*)\s*)'; + + // matches valid parenthesised function parameters: + // + // "text" + // $foo, $bar, "text" + // $foo|bar, "foo"|bar, $foo->bar($foo)|bar + $this->_parenth_param_regexp = '(?:\((?:\w+|' + . $this->_param_regexp . '(?:\s*,\s*(?:(?:\w+|' + . $this->_param_regexp . ')))*)?\))'; + + // matches valid function call: + // foo() + // foo_bar($foo) + // _foo_bar($foo,"bar") + // foo123($foo,$foo->bar(),"foo") + $this->_func_call_regexp = '(?:' . $this->_func_regexp . '\s*(?:' + . $this->_parenth_param_regexp . '))'; + } + + /** + * compile a resource + * + * sets $compiled_content to the compiled source + * @param string $resource_name + * @param string $source_content + * @param string $compiled_content + * @return true + */ + function _compile_file($resource_name, $source_content, &$compiled_content) + { + + if ($this->security) { + // do not allow php syntax to be executed unless specified + if ($this->php_handling == SMARTY_PHP_ALLOW && + !$this->security_settings['PHP_HANDLING']) { + $this->php_handling = SMARTY_PHP_PASSTHRU; + } + } + + $this->_load_filters(); + + $this->_current_file = $resource_name; + $this->_current_line_no = 1; + $ldq = preg_quote($this->left_delimiter, '~'); + $rdq = preg_quote($this->right_delimiter, '~'); + + // run template source through prefilter functions + if (count($this->_plugins['prefilter']) > 0) { + foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { + if ($prefilter === false) continue; + if ($prefilter[3] || is_callable($prefilter[0])) { + $source_content = call_user_func_array($prefilter[0], + array($source_content, &$this)); + $this->_plugins['prefilter'][$filter_name][3] = true; + } else { + $this->_trigger_fatal_error("[plugin] prefilter '$filter_name' is not implemented"); + } + } + } + + /* fetch all special blocks */ + $search = "~{$ldq}\*(.*?)\*{$rdq}|{$ldq}\s*literal\s*{$rdq}(.*?){$ldq}\s*/literal\s*{$rdq}|{$ldq}\s*php\s*{$rdq}(.*?){$ldq}\s*/php\s*{$rdq}~s"; + + preg_match_all($search, $source_content, $match, PREG_SET_ORDER); + $this->_folded_blocks = $match; + reset($this->_folded_blocks); + + /* replace special blocks by "{php}" */ + $source_content = preg_replace($search.'e', "'" + . $this->_quote_replace($this->left_delimiter) . 'php' + . "' . str_repeat(\"\n\", substr_count('\\0', \"\n\")) .'" + . $this->_quote_replace($this->right_delimiter) + . "'" + , $source_content); + + /* Gather all template tags. */ + preg_match_all("~{$ldq}\s*(.*?)\s*{$rdq}~s", $source_content, $_match); + $template_tags = $_match[1]; + /* Split content by template tags to obtain non-template content. */ + $text_blocks = preg_split("~{$ldq}.*?{$rdq}~s", $source_content); + + /* loop through text blocks */ + for ($curr_tb = 0, $for_max = count($text_blocks); $curr_tb < $for_max; $curr_tb++) { + /* match anything resembling php tags */ + if (preg_match_all('~(<\?(?:\w+|=)?|\?>|language\s*=\s*[\"\']?\s*php\s*[\"\']?)~is', $text_blocks[$curr_tb], $sp_match)) { + /* replace tags with placeholders to prevent recursive replacements */ + $sp_match[1] = array_unique($sp_match[1]); + usort($sp_match[1], '_smarty_sort_length'); + for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { + $text_blocks[$curr_tb] = str_replace($sp_match[1][$curr_sp],'%%%SMARTYSP'.$curr_sp.'%%%',$text_blocks[$curr_tb]); + } + /* process each one */ + for ($curr_sp = 0, $for_max2 = count($sp_match[1]); $curr_sp < $for_max2; $curr_sp++) { + if ($this->php_handling == SMARTY_PHP_PASSTHRU) { + /* echo php contents */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '<?php echo \''.str_replace("'", "\'", $sp_match[1][$curr_sp]).'\'; ?>'."\n", $text_blocks[$curr_tb]); + } else if ($this->php_handling == SMARTY_PHP_QUOTE) { + /* quote php tags */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', htmlspecialchars($sp_match[1][$curr_sp]), $text_blocks[$curr_tb]); + } else if ($this->php_handling == SMARTY_PHP_REMOVE) { + /* remove php tags */ + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', '', $text_blocks[$curr_tb]); + } else { + /* SMARTY_PHP_ALLOW, but echo non php starting tags */ + $sp_match[1][$curr_sp] = preg_replace('~(<\?(?!php|=|$))~i', '<?php echo \'\\1\'?>'."\n", $sp_match[1][$curr_sp]); + $text_blocks[$curr_tb] = str_replace('%%%SMARTYSP'.$curr_sp.'%%%', $sp_match[1][$curr_sp], $text_blocks[$curr_tb]); + } + } + } + } + + /* Compile the template tags into PHP code. */ + $compiled_tags = array(); + for ($i = 0, $for_max = count($template_tags); $i < $for_max; $i++) { + $this->_current_line_no += substr_count($text_blocks[$i], "\n"); + $compiled_tags[] = $this->_compile_tag($template_tags[$i]); + $this->_current_line_no += substr_count($template_tags[$i], "\n"); + } + if (count($this->_tag_stack)>0) { + list($_open_tag, $_line_no) = end($this->_tag_stack); + $this->_syntax_error("unclosed tag \{$_open_tag} (opened line $_line_no).", E_USER_ERROR, __FILE__, __LINE__); + return; + } + + /* Reformat $text_blocks between 'strip' and '/strip' tags, + removing spaces, tabs and newlines. */ + $strip = false; + for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { + if ($compiled_tags[$i] == '{strip}') { + $compiled_tags[$i] = ''; + $strip = true; + /* remove leading whitespaces */ + $text_blocks[$i + 1] = ltrim($text_blocks[$i + 1]); + } + if ($strip) { + /* strip all $text_blocks before the next '/strip' */ + for ($j = $i + 1; $j < $for_max; $j++) { + /* remove leading and trailing whitespaces of each line */ + $text_blocks[$j] = preg_replace('![\t ]*[\r\n]+[\t ]*!', '', $text_blocks[$j]); + if ($compiled_tags[$j] == '{/strip}') { + /* remove trailing whitespaces from the last text_block */ + $text_blocks[$j] = rtrim($text_blocks[$j]); + } + $text_blocks[$j] = "<?php echo '" . strtr($text_blocks[$j], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>"; + if ($compiled_tags[$j] == '{/strip}') { + $compiled_tags[$j] = "\n"; /* slurped by php, but necessary + if a newline is following the closing strip-tag */ + $strip = false; + $i = $j; + break; + } + } + } + } + $compiled_content = ''; + + $tag_guard = '%%%SMARTYOTG' . md5(uniqid(rand(), true)) . '%%%'; + + /* Interleave the compiled contents and text blocks to get the final result. */ + for ($i = 0, $for_max = count($compiled_tags); $i < $for_max; $i++) { + if ($compiled_tags[$i] == '') { + // tag result empty, remove first newline from following text block + $text_blocks[$i+1] = preg_replace('~^(\r\n|\r|\n)~', '', $text_blocks[$i+1]); + } + // replace legit PHP tags with placeholder + $text_blocks[$i] = str_replace('<?', $tag_guard, $text_blocks[$i]); + $compiled_tags[$i] = str_replace('<?', $tag_guard, $compiled_tags[$i]); + + $compiled_content .= $text_blocks[$i] . $compiled_tags[$i]; + } + $compiled_content .= str_replace('<?', $tag_guard, $text_blocks[$i]); + + // escape php tags created by interleaving + $compiled_content = str_replace('<?', "<?php echo '<?' ?>\n", $compiled_content); + $compiled_content = preg_replace("~(?<!')language\s*=\s*[\"\']?\s*php\s*[\"\']?~", "<?php echo 'language=php' ?>\n", $compiled_content); + + // recover legit tags + $compiled_content = str_replace($tag_guard, '<?', $compiled_content); + + // remove \n from the end of the file, if any + if (strlen($compiled_content) && (substr($compiled_content, -1) == "\n") ) { + $compiled_content = substr($compiled_content, 0, -1); + } + + if (!empty($this->_cache_serial)) { + $compiled_content = "<?php \$this->_cache_serials['".$this->_cache_include."'] = '".$this->_cache_serial."'; ?>" . $compiled_content; + } + + // run compiled template through postfilter functions + if (count($this->_plugins['postfilter']) > 0) { + foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { + if ($postfilter === false) continue; + if ($postfilter[3] || is_callable($postfilter[0])) { + $compiled_content = call_user_func_array($postfilter[0], + array($compiled_content, &$this)); + $this->_plugins['postfilter'][$filter_name][3] = true; + } else { + $this->_trigger_fatal_error("Smarty plugin error: postfilter '$filter_name' is not implemented"); + } + } + } + + // put header at the top of the compiled template + $template_header = "<?php /* Smarty version ".$this->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; + $template_header .= " compiled from ".strtr(urlencode($resource_name), array('%2F'=>'/', '%3A'=>':'))." */ ?>\n"; + + /* Emit code to load needed plugins. */ + $this->_plugins_code = ''; + if (count($this->_plugin_info)) { + $_plugins_params = "array('plugins' => array("; + foreach ($this->_plugin_info as $plugin_type => $plugins) { + foreach ($plugins as $plugin_name => $plugin_info) { + $_plugins_params .= "array('$plugin_type', '$plugin_name', '" . strtr($plugin_info[0], array("'" => "\\'", "\\" => "\\\\")) . "', $plugin_info[1], "; + $_plugins_params .= $plugin_info[2] ? 'true),' : 'false),'; + } + } + $_plugins_params .= '))'; + $plugins_code = "<?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php');\nsmarty_core_load_plugins($_plugins_params, \$this); ?>\n"; + $template_header .= $plugins_code; + $this->_plugin_info = array(); + $this->_plugins_code = $plugins_code; + } + + if ($this->_init_smarty_vars) { + $template_header .= "<?php require_once(SMARTY_CORE_DIR . 'core.assign_smarty_interface.php');\nsmarty_core_assign_smarty_interface(null, \$this); ?>\n"; + $this->_init_smarty_vars = false; + } + + $compiled_content = $template_header . $compiled_content; + return true; + } + + /** + * Compile a template tag + * + * @param string $template_tag + * @return string + */ + function _compile_tag($template_tag) + { + /* Matched comment. */ + if (substr($template_tag, 0, 1) == '*' && substr($template_tag, -1) == '*') + return ''; + + /* Split tag into two three parts: command, command modifiers and the arguments. */ + if(! preg_match('~^(?:(' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp + . '|\/?' . $this->_reg_obj_regexp . '|\/?' . $this->_func_regexp . ')(' . $this->_mod_regexp . '*)) + (?:\s+(.*))?$ + ~xs', $template_tag, $match)) { + $this->_syntax_error("unrecognized tag: $template_tag", E_USER_ERROR, __FILE__, __LINE__); + } + + $tag_command = $match[1]; + $tag_modifier = isset($match[2]) ? $match[2] : null; + $tag_args = isset($match[3]) ? $match[3] : null; + + if (preg_match('~^' . $this->_num_const_regexp . '|' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '$~', $tag_command)) { + /* tag name is a variable or object */ + $_return = $this->_parse_var_props($tag_command . $tag_modifier); + return "<?php echo $_return; ?>" . $this->_additional_newline; + } + + /* If the tag name is a registered object, we process it. */ + if (preg_match('~^\/?' . $this->_reg_obj_regexp . '$~', $tag_command)) { + return $this->_compile_registered_object_tag($tag_command, $this->_parse_attrs($tag_args), $tag_modifier); + } + + switch ($tag_command) { + case 'include': + return $this->_compile_include_tag($tag_args); + + case 'include_php': + return $this->_compile_include_php_tag($tag_args); + + case 'if': + $this->_push_tag('if'); + return $this->_compile_if_tag($tag_args); + + case 'else': + list($_open_tag) = end($this->_tag_stack); + if ($_open_tag != 'if' && $_open_tag != 'elseif') + $this->_syntax_error('unexpected {else}', E_USER_ERROR, __FILE__, __LINE__); + else + $this->_push_tag('else'); + return '<?php else: ?>'; + + case 'elseif': + list($_open_tag) = end($this->_tag_stack); + if ($_open_tag != 'if' && $_open_tag != 'elseif') + $this->_syntax_error('unexpected {elseif}', E_USER_ERROR, __FILE__, __LINE__); + if ($_open_tag == 'if') + $this->_push_tag('elseif'); + return $this->_compile_if_tag($tag_args, true); + + case '/if': + $this->_pop_tag('if'); + return '<?php endif; ?>'; + + case 'capture': + return $this->_compile_capture_tag(true, $tag_args); + + case '/capture': + return $this->_compile_capture_tag(false); + + case 'ldelim': + return $this->left_delimiter; + + case 'rdelim': + return $this->right_delimiter; + + case 'section': + $this->_push_tag('section'); + return $this->_compile_section_start($tag_args); + + case 'sectionelse': + $this->_push_tag('sectionelse'); + return "<?php endfor; else: ?>"; + break; + + case '/section': + $_open_tag = $this->_pop_tag('section'); + if ($_open_tag == 'sectionelse') + return "<?php endif; ?>"; + else + return "<?php endfor; endif; ?>"; + + case 'foreach': + $this->_push_tag('foreach'); + return $this->_compile_foreach_start($tag_args); + break; + + case 'foreachelse': + $this->_push_tag('foreachelse'); + return "<?php endforeach; else: ?>"; + + case '/foreach': + $_open_tag = $this->_pop_tag('foreach'); + if ($_open_tag == 'foreachelse') + return "<?php endif; unset(\$_from); ?>"; + else + return "<?php endforeach; endif; unset(\$_from); ?>"; + break; + + case 'strip': + case '/strip': + if (substr($tag_command, 0, 1)=='/') { + $this->_pop_tag('strip'); + if (--$this->_strip_depth==0) { /* outermost closing {/strip} */ + $this->_additional_newline = "\n"; + return '{' . $tag_command . '}'; + } + } else { + $this->_push_tag('strip'); + if ($this->_strip_depth++==0) { /* outermost opening {strip} */ + $this->_additional_newline = ""; + return '{' . $tag_command . '}'; + } + } + return ''; + + case 'php': + /* handle folded tags replaced by {php} */ + list(, $block) = each($this->_folded_blocks); + $this->_current_line_no += substr_count($block[0], "\n"); + /* the number of matched elements in the regexp in _compile_file() + determins the type of folded tag that was found */ + switch (count($block)) { + case 2: /* comment */ + return ''; + + case 3: /* literal */ + return "<?php echo '" . strtr($block[2], array("'"=>"\'", "\\"=>"\\\\")) . "'; ?>" . $this->_additional_newline; + + case 4: /* php */ + if ($this->security && !$this->security_settings['PHP_TAGS']) { + $this->_syntax_error("(secure mode) php tags not permitted", E_USER_WARNING, __FILE__, __LINE__); + return; + } + return '<?php ' . $block[3] .' ?>'; + } + break; + + case 'insert': + return $this->_compile_insert_tag($tag_args); + + default: + if ($this->_compile_compiler_tag($tag_command, $tag_args, $output)) { + return $output; + } else if ($this->_compile_block_tag($tag_command, $tag_args, $tag_modifier, $output)) { + return $output; + } else if ($this->_compile_custom_tag($tag_command, $tag_args, $tag_modifier, $output)) { + return $output; + } else { + $this->_syntax_error("unrecognized tag '$tag_command'", E_USER_ERROR, __FILE__, __LINE__); + } + + } + } + + + /** + * compile the custom compiler tag + * + * sets $output to the compiled custom compiler tag + * @param string $tag_command + * @param string $tag_args + * @param string $output + * @return boolean + */ + function _compile_compiler_tag($tag_command, $tag_args, &$output) + { + $found = false; + $have_function = true; + + /* + * First we check if the compiler function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['compiler'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['compiler'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "compiler function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('compiler', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_compiler_' . $tag_command; + if (!is_callable($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['compiler'][$tag_command] = array($plugin_func, null, null, null, true); + } + } + + /* + * True return value means that we either found a plugin or a + * dynamically registered function. False means that we didn't and the + * compiler should now emit code to load custom function plugin for this + * tag. + */ + if ($found) { + if ($have_function) { + $output = call_user_func_array($plugin_func, array($tag_args, &$this)); + if($output != '') { + $output = '<?php ' . $this->_push_cacheable_state('compiler', $tag_command) + . $output + . $this->_pop_cacheable_state('compiler', $tag_command) . ' ?>'; + } + } else { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + } + return true; + } else { + return false; + } + } + + + /** + * compile block function tag + * + * sets $output to compiled block function tag + * @param string $tag_command + * @param string $tag_args + * @param string $tag_modifier + * @param string $output + * @return boolean + */ + function _compile_block_tag($tag_command, $tag_args, $tag_modifier, &$output) + { + if (substr($tag_command, 0, 1) == '/') { + $start_tag = false; + $tag_command = substr($tag_command, 1); + } else + $start_tag = true; + + $found = false; + $have_function = true; + + /* + * First we check if the block function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['block'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['block'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "block function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('block', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_block_' . $tag_command; + if (!function_exists($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['block'][$tag_command] = array($plugin_func, null, null, null, true); + + } + } + + if (!$found) { + return false; + } else if (!$have_function) { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + return true; + } + + /* + * Even though we've located the plugin function, compilation + * happens only once, so the plugin will still need to be loaded + * at runtime for future requests. + */ + $this->_add_plugin('block', $tag_command); + + if ($start_tag) + $this->_push_tag($tag_command); + else + $this->_pop_tag($tag_command); + + if ($start_tag) { + $output = '<?php ' . $this->_push_cacheable_state('block', $tag_command); + $attrs = $this->_parse_attrs($tag_args); + $_cache_attrs=''; + $arg_list = $this->_compile_arg_list('block', $tag_command, $attrs, $_cache_attrs); + $output .= "$_cache_attrs\$this->_tag_stack[] = array('$tag_command', array(".implode(',', $arg_list).')); '; + $output .= '$_block_repeat=true;' . $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], null, $this, $_block_repeat);'; + $output .= 'while ($_block_repeat) { ob_start(); ?>'; + } else { + $output = '<?php $_block_content = ob_get_contents(); ob_end_clean(); '; + $_out_tag_text = $this->_compile_plugin_call('block', $tag_command).'($this->_tag_stack[count($this->_tag_stack)-1][1], $_block_content, $this, $_block_repeat)'; + if ($tag_modifier != '') { + $this->_parse_modifiers($_out_tag_text, $tag_modifier); + } + $output .= '$_block_repeat=false;echo ' . $_out_tag_text . '; } '; + $output .= " array_pop(\$this->_tag_stack); " . $this->_pop_cacheable_state('block', $tag_command) . '?>'; + } + + return true; + } + + + /** + * compile custom function tag + * + * @param string $tag_command + * @param string $tag_args + * @param string $tag_modifier + * @return string + */ + function _compile_custom_tag($tag_command, $tag_args, $tag_modifier, &$output) + { + $found = false; + $have_function = true; + + /* + * First we check if the custom function has already been registered + * or loaded from a plugin file. + */ + if (isset($this->_plugins['function'][$tag_command])) { + $found = true; + $plugin_func = $this->_plugins['function'][$tag_command][0]; + if (!is_callable($plugin_func)) { + $message = "custom function '$tag_command' is not implemented"; + $have_function = false; + } + } + /* + * Otherwise we need to load plugin file and look for the function + * inside it. + */ + else if ($plugin_file = $this->_get_plugin_filepath('function', $tag_command)) { + $found = true; + + include_once $plugin_file; + + $plugin_func = 'smarty_function_' . $tag_command; + if (!function_exists($plugin_func)) { + $message = "plugin function $plugin_func() not found in $plugin_file\n"; + $have_function = false; + } else { + $this->_plugins['function'][$tag_command] = array($plugin_func, null, null, null, true); + + } + } + + if (!$found) { + return false; + } else if (!$have_function) { + $this->_syntax_error($message, E_USER_WARNING, __FILE__, __LINE__); + return true; + } + + /* declare plugin to be loaded on display of the template that + we compile right now */ + $this->_add_plugin('function', $tag_command); + + $_cacheable_state = $this->_push_cacheable_state('function', $tag_command); + $attrs = $this->_parse_attrs($tag_args); + $_cache_attrs = ''; + $arg_list = $this->_compile_arg_list('function', $tag_command, $attrs, $_cache_attrs); + + $output = $this->_compile_plugin_call('function', $tag_command).'(array('.implode(',', $arg_list)."), \$this)"; + if($tag_modifier != '') { + $this->_parse_modifiers($output, $tag_modifier); + } + + if($output != '') { + $output = '<?php ' . $_cacheable_state . $_cache_attrs . 'echo ' . $output . ';' + . $this->_pop_cacheable_state('function', $tag_command) . "?>" . $this->_additional_newline; + } + + return true; + } + + /** + * compile a registered object tag + * + * @param string $tag_command + * @param array $attrs + * @param string $tag_modifier + * @return string + */ + function _compile_registered_object_tag($tag_command, $attrs, $tag_modifier) + { + if (substr($tag_command, 0, 1) == '/') { + $start_tag = false; + $tag_command = substr($tag_command, 1); + } else { + $start_tag = true; + } + + list($object, $obj_comp) = explode('->', $tag_command); + + $arg_list = array(); + if(count($attrs)) { + $_assign_var = false; + foreach ($attrs as $arg_name => $arg_value) { + if($arg_name == 'assign') { + $_assign_var = $arg_value; + unset($attrs['assign']); + continue; + } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + + if($this->_reg_objects[$object][2]) { + // smarty object argument format + $args = "array(".implode(',', (array)$arg_list)."), \$this"; + } else { + // traditional argument format + $args = implode(',', array_values($attrs)); + if (empty($args)) { + $args = ''; + } + } + + $prefix = ''; + $postfix = ''; + $newline = ''; + if(!is_object($this->_reg_objects[$object][0])) { + $this->_trigger_fatal_error("registered '$object' is not an object" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } elseif(!empty($this->_reg_objects[$object][1]) && !in_array($obj_comp, $this->_reg_objects[$object][1])) { + $this->_trigger_fatal_error("'$obj_comp' is not a registered component of object '$object'", $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } elseif(method_exists($this->_reg_objects[$object][0], $obj_comp)) { + // method + if(in_array($obj_comp, $this->_reg_objects[$object][3])) { + // block method + if ($start_tag) { + $prefix = "\$this->_tag_stack[] = array('$obj_comp', $args); "; + $prefix .= "\$_block_repeat=true; \$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], null, \$this, \$_block_repeat); "; + $prefix .= "while (\$_block_repeat) { ob_start();"; + $return = null; + $postfix = ''; + } else { + $prefix = "\$_obj_block_content = ob_get_contents(); ob_end_clean(); \$_block_repeat=false;"; + $return = "\$this->_reg_objects['$object'][0]->$obj_comp(\$this->_tag_stack[count(\$this->_tag_stack)-1][1], \$_obj_block_content, \$this, \$_block_repeat)"; + $postfix = "} array_pop(\$this->_tag_stack);"; + } + } else { + // non-block method + $return = "\$this->_reg_objects['$object'][0]->$obj_comp($args)"; + } + } else { + // property + $return = "\$this->_reg_objects['$object'][0]->$obj_comp"; + } + + if($return != null) { + if($tag_modifier != '') { + $this->_parse_modifiers($return, $tag_modifier); + } + + if(!empty($_assign_var)) { + $output = "\$this->assign('" . $this->_dequote($_assign_var) ."', $return);"; + } else { + $output = 'echo ' . $return . ';'; + $newline = $this->_additional_newline; + } + } else { + $output = ''; + } + + return '<?php ' . $prefix . $output . $postfix . "?>" . $newline; + } + + /** + * Compile {insert ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_insert_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $name = $this->_dequote($attrs['name']); + + if (empty($name)) { + return $this->_syntax_error("missing insert name", E_USER_ERROR, __FILE__, __LINE__); + } + + if (!preg_match('~^\w+$~', $name)) { + return $this->_syntax_error("'insert: 'name' must be an insert function name", E_USER_ERROR, __FILE__, __LINE__); + } + + if (!empty($attrs['script'])) { + $delayed_loading = true; + } else { + $delayed_loading = false; + } + + foreach ($attrs as $arg_name => $arg_value) { + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + + $this->_add_plugin('insert', $name, $delayed_loading); + + $_params = "array('args' => array(".implode(', ', (array)$arg_list)."))"; + + return "<?php require_once(SMARTY_CORE_DIR . 'core.run_insert_handler.php');\necho smarty_core_run_insert_handler($_params, \$this); ?>" . $this->_additional_newline; + } + + /** + * Compile {include ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_include_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + if (empty($attrs['file'])) { + $this->_syntax_error("missing 'file' attribute in include tag", E_USER_ERROR, __FILE__, __LINE__); + } + + foreach ($attrs as $arg_name => $arg_value) { + if ($arg_name == 'file') { + $include_file = $arg_value; + continue; + } else if ($arg_name == 'assign') { + $assign_var = $arg_value; + continue; + } + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + + $output = '<?php '; + + if (isset($assign_var)) { + $output .= "ob_start();\n"; + } + + $output .= + "\$_smarty_tpl_vars = \$this->_tpl_vars;\n"; + + + $_params = "array('smarty_include_tpl_file' => " . $include_file . ", 'smarty_include_vars' => array(".implode(',', (array)$arg_list)."))"; + $output .= "\$this->_smarty_include($_params);\n" . + "\$this->_tpl_vars = \$_smarty_tpl_vars;\n" . + "unset(\$_smarty_tpl_vars);\n"; + + if (isset($assign_var)) { + $output .= "\$this->assign(" . $assign_var . ", ob_get_contents()); ob_end_clean();\n"; + } + + $output .= ' ?>'; + + return $output; + + } + + /** + * Compile {include ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_include_php_tag($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + + if (empty($attrs['file'])) { + $this->_syntax_error("missing 'file' attribute in include_php tag", E_USER_ERROR, __FILE__, __LINE__); + } + + $assign_var = (empty($attrs['assign'])) ? '' : $this->_dequote($attrs['assign']); + $once_var = (empty($attrs['once']) || $attrs['once']=='false') ? 'false' : 'true'; + + $arg_list = array(); + foreach($attrs as $arg_name => $arg_value) { + if($arg_name != 'file' AND $arg_name != 'once' AND $arg_name != 'assign') { + if(is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + + $_params = "array('smarty_file' => " . $attrs['file'] . ", 'smarty_assign' => '$assign_var', 'smarty_once' => $once_var, 'smarty_include_vars' => array(".implode(',', $arg_list)."))"; + + return "<?php require_once(SMARTY_CORE_DIR . 'core.smarty_include_php.php');\nsmarty_core_smarty_include_php($_params, \$this); ?>" . $this->_additional_newline; + } + + + /** + * Compile {section ...} tag + * + * @param string $tag_args + * @return string + */ + function _compile_section_start($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + $output = '<?php '; + $section_name = $attrs['name']; + if (empty($section_name)) { + $this->_syntax_error("missing section name", E_USER_ERROR, __FILE__, __LINE__); + } + + $output .= "unset(\$this->_sections[$section_name]);\n"; + $section_props = "\$this->_sections[$section_name]"; + + foreach ($attrs as $attr_name => $attr_value) { + switch ($attr_name) { + case 'loop': + $output .= "{$section_props}['loop'] = is_array(\$_loop=$attr_value) ? count(\$_loop) : max(0, (int)\$_loop); unset(\$_loop);\n"; + break; + + case 'show': + if (is_bool($attr_value)) + $show_attr_value = $attr_value ? 'true' : 'false'; + else + $show_attr_value = "(bool)$attr_value"; + $output .= "{$section_props}['show'] = $show_attr_value;\n"; + break; + + case 'name': + $output .= "{$section_props}['$attr_name'] = $attr_value;\n"; + break; + + case 'max': + case 'start': + $output .= "{$section_props}['$attr_name'] = (int)$attr_value;\n"; + break; + + case 'step': + $output .= "{$section_props}['$attr_name'] = ((int)$attr_value) == 0 ? 1 : (int)$attr_value;\n"; + break; + + default: + $this->_syntax_error("unknown section attribute - '$attr_name'", E_USER_ERROR, __FILE__, __LINE__); + break; + } + } + + if (!isset($attrs['show'])) + $output .= "{$section_props}['show'] = true;\n"; + + if (!isset($attrs['loop'])) + $output .= "{$section_props}['loop'] = 1;\n"; + + if (!isset($attrs['max'])) + $output .= "{$section_props}['max'] = {$section_props}['loop'];\n"; + else + $output .= "if ({$section_props}['max'] < 0)\n" . + " {$section_props}['max'] = {$section_props}['loop'];\n"; + + if (!isset($attrs['step'])) + $output .= "{$section_props}['step'] = 1;\n"; + + if (!isset($attrs['start'])) + $output .= "{$section_props}['start'] = {$section_props}['step'] > 0 ? 0 : {$section_props}['loop']-1;\n"; + else { + $output .= "if ({$section_props}['start'] < 0)\n" . + " {$section_props}['start'] = max({$section_props}['step'] > 0 ? 0 : -1, {$section_props}['loop'] + {$section_props}['start']);\n" . + "else\n" . + " {$section_props}['start'] = min({$section_props}['start'], {$section_props}['step'] > 0 ? {$section_props}['loop'] : {$section_props}['loop']-1);\n"; + } + + $output .= "if ({$section_props}['show']) {\n"; + if (!isset($attrs['start']) && !isset($attrs['step']) && !isset($attrs['max'])) { + $output .= " {$section_props}['total'] = {$section_props}['loop'];\n"; + } else { + $output .= " {$section_props}['total'] = min(ceil(({$section_props}['step'] > 0 ? {$section_props}['loop'] - {$section_props}['start'] : {$section_props}['start']+1)/abs({$section_props}['step'])), {$section_props}['max']);\n"; + } + $output .= " if ({$section_props}['total'] == 0)\n" . + " {$section_props}['show'] = false;\n" . + "} else\n" . + " {$section_props}['total'] = 0;\n"; + + $output .= "if ({$section_props}['show']):\n"; + $output .= " + for ({$section_props}['index'] = {$section_props}['start'], {$section_props}['iteration'] = 1; + {$section_props}['iteration'] <= {$section_props}['total']; + {$section_props}['index'] += {$section_props}['step'], {$section_props}['iteration']++):\n"; + $output .= "{$section_props}['rownum'] = {$section_props}['iteration'];\n"; + $output .= "{$section_props}['index_prev'] = {$section_props}['index'] - {$section_props}['step'];\n"; + $output .= "{$section_props}['index_next'] = {$section_props}['index'] + {$section_props}['step'];\n"; + $output .= "{$section_props}['first'] = ({$section_props}['iteration'] == 1);\n"; + $output .= "{$section_props}['last'] = ({$section_props}['iteration'] == {$section_props}['total']);\n"; + + $output .= "?>"; + + return $output; + } + + + /** + * Compile {foreach ...} tag. + * + * @param string $tag_args + * @return string + */ + function _compile_foreach_start($tag_args) + { + $attrs = $this->_parse_attrs($tag_args); + $arg_list = array(); + + if (empty($attrs['from'])) { + return $this->_syntax_error("foreach: missing 'from' attribute", E_USER_ERROR, __FILE__, __LINE__); + } + $from = $attrs['from']; + + if (empty($attrs['item'])) { + return $this->_syntax_error("foreach: missing 'item' attribute", E_USER_ERROR, __FILE__, __LINE__); + } + $item = $this->_dequote($attrs['item']); + if (!preg_match('~^\w+$~', $item)) { + return $this->_syntax_error("foreach: 'item' must be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); + } + + if (isset($attrs['key'])) { + $key = $this->_dequote($attrs['key']); + if (!preg_match('~^\w+$~', $key)) { + return $this->_syntax_error("foreach: 'key' must to be a variable name (literal string)", E_USER_ERROR, __FILE__, __LINE__); + } + $key_part = "\$this->_tpl_vars['$key'] => "; + } else { + $key = null; + $key_part = ''; + } + + if (isset($attrs['name'])) { + $name = $attrs['name']; + } else { + $name = null; + } + + $output = '<?php '; + $output .= "\$_from = $from; if (!is_array(\$_from) && !is_object(\$_from)) { settype(\$_from, 'array'); }"; + if (isset($name)) { + $foreach_props = "\$this->_foreach[$name]"; + $output .= "{$foreach_props} = array('total' => count(\$_from), 'iteration' => 0);\n"; + $output .= "if ({$foreach_props}['total'] > 0):\n"; + $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; + $output .= " {$foreach_props}['iteration']++;\n"; + } else { + $output .= "if (count(\$_from)):\n"; + $output .= " foreach (\$_from as $key_part\$this->_tpl_vars['$item']):\n"; + } + $output .= '?>'; + + return $output; + } + + + /** + * Compile {capture} .. {/capture} tags + * + * @param boolean $start true if this is the {capture} tag + * @param string $tag_args + * @return string + */ + + function _compile_capture_tag($start, $tag_args = '') + { + $attrs = $this->_parse_attrs($tag_args); + + if ($start) { + $buffer = isset($attrs['name']) ? $attrs['name'] : "'default'"; + $assign = isset($attrs['assign']) ? $attrs['assign'] : null; + $append = isset($attrs['append']) ? $attrs['append'] : null; + + $output = "<?php ob_start(); ?>"; + $this->_capture_stack[] = array($buffer, $assign, $append); + } else { + list($buffer, $assign, $append) = array_pop($this->_capture_stack); + $output = "<?php \$this->_smarty_vars['capture'][$buffer] = ob_get_contents(); "; + if (isset($assign)) { + $output .= " \$this->assign($assign, ob_get_contents());"; + } + if (isset($append)) { + $output .= " \$this->append($append, ob_get_contents());"; + } + $output .= "ob_end_clean(); ?>"; + } + + return $output; + } + + /** + * Compile {if ...} tag + * + * @param string $tag_args + * @param boolean $elseif if true, uses elseif instead of if + * @return string + */ + function _compile_if_tag($tag_args, $elseif = false) + { + + /* Tokenize args for 'if' tag. */ + preg_match_all('~(?> + ' . $this->_obj_call_regexp . '(?:' . $this->_mod_regexp . '*)? | # valid object call + ' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)? | # var or quoted string + \-?0[xX][0-9a-fA-F]+|\-?\d+(?:\.\d+)?|\.\d+|!==|===|==|!=|<>|<<|>>|<=|>=|\&\&|\|\||\(|\)|,|\!|\^|=|\&|\~|<|>|\||\%|\+|\-|\/|\*|\@ | # valid non-word token + \b\w+\b | # valid word token + \S+ # anything else + )~x', $tag_args, $match); + + $tokens = $match[0]; + + if(empty($tokens)) { + $_error_msg = $elseif ? "'elseif'" : "'if'"; + $_error_msg .= ' statement requires arguments'; + $this->_syntax_error($_error_msg, E_USER_ERROR, __FILE__, __LINE__); + } + + + // make sure we have balanced parenthesis + $token_count = array_count_values($tokens); + if(isset($token_count['(']) && $token_count['('] != $token_count[')']) { + $this->_syntax_error("unbalanced parenthesis in if statement", E_USER_ERROR, __FILE__, __LINE__); + } + + $is_arg_stack = array(); + + for ($i = 0; $i < count($tokens); $i++) { + + $token = &$tokens[$i]; + + switch (strtolower($token)) { + case '!': + case '%': + case '!==': + case '==': + case '===': + case '>': + case '<': + case '!=': + case '<>': + case '<<': + case '>>': + case '<=': + case '>=': + case '&&': + case '||': + case '|': + case '^': + case '&': + case '~': + case ')': + case ',': + case '+': + case '-': + case '*': + case '/': + case '@': + break; + + case 'eq': + $token = '=='; + break; + + case 'ne': + case 'neq': + $token = '!='; + break; + + case 'lt': + $token = '<'; + break; + + case 'le': + case 'lte': + $token = '<='; + break; + + case 'gt': + $token = '>'; + break; + + case 'ge': + case 'gte': + $token = '>='; + break; + + case 'and': + $token = '&&'; + break; + + case 'or': + $token = '||'; + break; + + case 'not': + $token = '!'; + break; + + case 'mod': + $token = '%'; + break; + + case '(': + array_push($is_arg_stack, $i); + break; + + case 'is': + /* If last token was a ')', we operate on the parenthesized + expression. The start of the expression is on the stack. + Otherwise, we operate on the last encountered token. */ + if ($tokens[$i-1] == ')') + $is_arg_start = array_pop($is_arg_stack); + else + $is_arg_start = $i-1; + /* Construct the argument for 'is' expression, so it knows + what to operate on. */ + $is_arg = implode(' ', array_slice($tokens, $is_arg_start, $i - $is_arg_start)); + + /* Pass all tokens from next one until the end to the + 'is' expression parsing function. The function will + return modified tokens, where the first one is the result + of the 'is' expression and the rest are the tokens it + didn't touch. */ + $new_tokens = $this->_parse_is_expr($is_arg, array_slice($tokens, $i+1)); + + /* Replace the old tokens with the new ones. */ + array_splice($tokens, $is_arg_start, count($tokens), $new_tokens); + + /* Adjust argument start so that it won't change from the + current position for the next iteration. */ + $i = $is_arg_start; + break; + + default: + if(preg_match('~^' . $this->_func_regexp . '$~', $token) ) { + // function call + if($this->security && + !in_array($token, $this->security_settings['IF_FUNCS'])) { + $this->_syntax_error("(secure mode) '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); + } + } elseif(preg_match('~^' . $this->_var_regexp . '$~', $token) && (strpos('+-*/^%&|', substr($token, -1)) === false) && isset($tokens[$i+1]) && $tokens[$i+1] == '(') { + // variable function call + $this->_syntax_error("variable function call '$token' not allowed in if statement", E_USER_ERROR, __FILE__, __LINE__); + } elseif(preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . '*)$~', $token)) { + // object or variable + $token = $this->_parse_var_props($token); + } elseif(is_numeric($token)) { + // number, skip it + } else { + $this->_syntax_error("unidentified token '$token'", E_USER_ERROR, __FILE__, __LINE__); + } + break; + } + } + + if ($elseif) + return '<?php elseif ('.implode(' ', $tokens).'): ?>'; + else + return '<?php if ('.implode(' ', $tokens).'): ?>'; + } + + + function _compile_arg_list($type, $name, $attrs, &$cache_code) { + $arg_list = array(); + + if (isset($type) && isset($name) + && isset($this->_plugins[$type]) + && isset($this->_plugins[$type][$name]) + && empty($this->_plugins[$type][$name][4]) + && is_array($this->_plugins[$type][$name][5]) + ) { + /* we have a list of parameters that should be cached */ + $_cache_attrs = $this->_plugins[$type][$name][5]; + $_count = $this->_cache_attrs_count++; + $cache_code = "\$_cache_attrs =& \$this->_smarty_cache_attrs('$this->_cache_serial','$_count');"; + + } else { + /* no parameters are cached */ + $_cache_attrs = null; + } + + foreach ($attrs as $arg_name => $arg_value) { + if (is_bool($arg_value)) + $arg_value = $arg_value ? 'true' : 'false'; + if (is_null($arg_value)) + $arg_value = 'null'; + if ($_cache_attrs && in_array($arg_name, $_cache_attrs)) { + $arg_list[] = "'$arg_name' => (\$this->_cache_including) ? \$_cache_attrs['$arg_name'] : (\$_cache_attrs['$arg_name']=$arg_value)"; + } else { + $arg_list[] = "'$arg_name' => $arg_value"; + } + } + return $arg_list; + } + + /** + * Parse is expression + * + * @param string $is_arg + * @param array $tokens + * @return array + */ + function _parse_is_expr($is_arg, $tokens) + { + $expr_end = 0; + $negate_expr = false; + + if (($first_token = array_shift($tokens)) == 'not') { + $negate_expr = true; + $expr_type = array_shift($tokens); + } else + $expr_type = $first_token; + + switch ($expr_type) { + case 'even': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; + } else + $expr = "!(1 & $is_arg)"; + break; + + case 'odd': + if (isset($tokens[$expr_end]) && $tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "(1 & ($is_arg / " . $this->_parse_var_props($expr_arg) . "))"; + } else + $expr = "(1 & $is_arg)"; + break; + + case 'div': + if (@$tokens[$expr_end] == 'by') { + $expr_end++; + $expr_arg = $tokens[$expr_end++]; + $expr = "!($is_arg % " . $this->_parse_var_props($expr_arg) . ")"; + } else { + $this->_syntax_error("expecting 'by' after 'div'", E_USER_ERROR, __FILE__, __LINE__); + } + break; + + default: + $this->_syntax_error("unknown 'is' expression - '$expr_type'", E_USER_ERROR, __FILE__, __LINE__); + break; + } + + if ($negate_expr) { + $expr = "!($expr)"; + } + + array_splice($tokens, 0, $expr_end, $expr); + + return $tokens; + } + + + /** + * Parse attribute string + * + * @param string $tag_args + * @return array + */ + function _parse_attrs($tag_args) + { + + /* Tokenize tag attributes. */ + preg_match_all('~(?:' . $this->_obj_call_regexp . '|' . $this->_qstr_regexp . ' | (?>[^"\'=\s]+) + )+ | + [=] + ~x', $tag_args, $match); + $tokens = $match[0]; + + $attrs = array(); + /* Parse state: + 0 - expecting attribute name + 1 - expecting '=' + 2 - expecting attribute value (not '=') */ + $state = 0; + + foreach ($tokens as $token) { + switch ($state) { + case 0: + /* If the token is a valid identifier, we set attribute name + and go to state 1. */ + if (preg_match('~^\w+$~', $token)) { + $attr_name = $token; + $state = 1; + } else + $this->_syntax_error("invalid attribute name: '$token'", E_USER_ERROR, __FILE__, __LINE__); + break; + + case 1: + /* If the token is '=', then we go to state 2. */ + if ($token == '=') { + $state = 2; + } else + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + break; + + case 2: + /* If token is not '=', we set the attribute value and go to + state 0. */ + if ($token != '=') { + /* We booleanize the token if it's a non-quoted possible + boolean value. */ + if (preg_match('~^(on|yes|true)$~', $token)) { + $token = 'true'; + } else if (preg_match('~^(off|no|false)$~', $token)) { + $token = 'false'; + } else if ($token == 'null') { + $token = 'null'; + } else if (preg_match('~^' . $this->_num_const_regexp . '|0[xX][0-9a-fA-F]+$~', $token)) { + /* treat integer literally */ + } else if (!preg_match('~^' . $this->_obj_call_regexp . '|' . $this->_var_regexp . '(?:' . $this->_mod_regexp . ')*$~', $token)) { + /* treat as a string, double-quote it escaping quotes */ + $token = '"'.addslashes($token).'"'; + } + + $attrs[$attr_name] = $token; + $state = 0; + } else + $this->_syntax_error("'=' cannot be an attribute value", E_USER_ERROR, __FILE__, __LINE__); + break; + } + $last_token = $token; + } + + if($state != 0) { + if($state == 1) { + $this->_syntax_error("expecting '=' after attribute name '$last_token'", E_USER_ERROR, __FILE__, __LINE__); + } else { + $this->_syntax_error("missing attribute value", E_USER_ERROR, __FILE__, __LINE__); + } + } + + $this->_parse_vars_props($attrs); + + return $attrs; + } + + /** + * compile multiple variables and section properties tokens into + * PHP code + * + * @param array $tokens + */ + function _parse_vars_props(&$tokens) + { + foreach($tokens as $key => $val) { + $tokens[$key] = $this->_parse_var_props($val); + } + } + + /** + * compile single variable and section properties token into + * PHP code + * + * @param string $val + * @param string $tag_attrs + * @return string + */ + function _parse_var_props($val) + { + $val = trim($val); + + if(preg_match('~^(' . $this->_obj_call_regexp . '|' . $this->_dvar_regexp . ')(' . $this->_mod_regexp . '*)$~', $val, $match)) { + // $ variable or object + $return = $this->_parse_var($match[1]); + $modifiers = $match[2]; + if (!empty($this->default_modifiers) && !preg_match('~(^|\|)smarty:nodefaults($|\|)~',$modifiers)) { + $_default_mod_string = implode('|',(array)$this->default_modifiers); + $modifiers = empty($modifiers) ? $_default_mod_string : $_default_mod_string . '|' . $modifiers; + } + $this->_parse_modifiers($return, $modifiers); + return $return; + } elseif (preg_match('~^' . $this->_db_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // double quoted text + preg_match('~^(' . $this->_db_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + $return = $this->_expand_quoted_text($match[1]); + if($match[2] != '') { + $this->_parse_modifiers($return, $match[2]); + } + return $return; + } + elseif(preg_match('~^' . $this->_num_const_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // numerical constant + preg_match('~^(' . $this->_num_const_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + if($match[2] != '') { + $this->_parse_modifiers($match[1], $match[2]); + return $match[1]; + } + } + elseif(preg_match('~^' . $this->_si_qstr_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // single quoted text + preg_match('~^(' . $this->_si_qstr_regexp . ')('. $this->_mod_regexp . '*)$~', $val, $match); + if($match[2] != '') { + $this->_parse_modifiers($match[1], $match[2]); + return $match[1]; + } + } + elseif(preg_match('~^' . $this->_cvar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // config var + return $this->_parse_conf_var($val); + } + elseif(preg_match('~^' . $this->_svar_regexp . '(?:' . $this->_mod_regexp . '*)$~', $val)) { + // section var + return $this->_parse_section_prop($val); + } + elseif(!in_array($val, $this->_permitted_tokens) && !is_numeric($val)) { + // literal string + return $this->_expand_quoted_text('"' . strtr($val, array('\\' => '\\\\', '"' => '\\"')) .'"'); + } + return $val; + } + + /** + * expand quoted text with embedded variables + * + * @param string $var_expr + * @return string + */ + function _expand_quoted_text($var_expr) + { + // if contains unescaped $, expand it + if(preg_match_all('~(?:\`(?<!\\\\)\$' . $this->_dvar_guts_regexp . '(?:' . $this->_obj_ext_regexp . ')*\`)|(?:(?<!\\\\)\$\w+(\[[a-zA-Z0-9]+\])*)~', $var_expr, $_match)) { + $_match = $_match[0]; + $_replace = array(); + foreach($_match as $_var) { + $_replace[$_var] = '".(' . $this->_parse_var(str_replace('`','',$_var)) . ')."'; + } + $var_expr = strtr($var_expr, $_replace); + $_return = preg_replace('~\.""|(?<!\\\\)""\.~', '', $var_expr); + } else { + $_return = $var_expr; + } + // replace double quoted literal string with single quotes + $_return = preg_replace('~^"([\s\w]+)"$~',"'\\1'",$_return); + return $_return; + } + + /** + * parse variable expression into PHP code + * + * @param string $var_expr + * @param string $output + * @return string + */ + function _parse_var($var_expr) + { + $_has_math = false; + $_math_vars = preg_split('~('.$this->_dvar_math_regexp.'|'.$this->_qstr_regexp.')~', $var_expr, -1, PREG_SPLIT_DELIM_CAPTURE); + + if(count($_math_vars) > 1) { + $_first_var = ""; + $_complete_var = ""; + $_output = ""; + // simple check if there is any math, to stop recursion (due to modifiers with "xx % yy" as parameter) + foreach($_math_vars as $_k => $_math_var) { + $_math_var = $_math_vars[$_k]; + + if(!empty($_math_var) || is_numeric($_math_var)) { + // hit a math operator, so process the stuff which came before it + if(preg_match('~^' . $this->_dvar_math_regexp . '$~', $_math_var)) { + $_has_math = true; + if(!empty($_complete_var) || is_numeric($_complete_var)) { + $_output .= $this->_parse_var($_complete_var); + } + + // just output the math operator to php + $_output .= $_math_var; + + if(empty($_first_var)) + $_first_var = $_complete_var; + + $_complete_var = ""; + } else { + $_complete_var .= $_math_var; + } + } + } + if($_has_math) { + if(!empty($_complete_var) || is_numeric($_complete_var)) + $_output .= $this->_parse_var($_complete_var); + + // get the modifiers working (only the last var from math + modifier is left) + $var_expr = $_complete_var; + } + } + + // prevent cutting of first digit in the number (we _definitly_ got a number if the first char is a digit) + if(is_numeric(substr($var_expr, 0, 1))) + $_var_ref = $var_expr; + else + $_var_ref = substr($var_expr, 1); + + if(!$_has_math) { + + // get [foo] and .foo and ->foo and (...) pieces + preg_match_all('~(?:^\w+)|' . $this->_obj_params_regexp . '|(?:' . $this->_var_bracket_regexp . ')|->\$?\w+|\.\$?\w+|\S+~', $_var_ref, $match); + + $_indexes = $match[0]; + $_var_name = array_shift($_indexes); + + /* Handle $smarty.* variable references as a special case. */ + if ($_var_name == 'smarty') { + /* + * If the reference could be compiled, use the compiled output; + * otherwise, fall back on the $smarty variable generated at + * run-time. + */ + if (($smarty_ref = $this->_compile_smarty_ref($_indexes)) !== null) { + $_output = $smarty_ref; + } else { + $_var_name = substr(array_shift($_indexes), 1); + $_output = "\$this->_smarty_vars['$_var_name']"; + } + } elseif(is_numeric($_var_name) && is_numeric(substr($var_expr, 0, 1))) { + // because . is the operator for accessing arrays thru inidizes we need to put it together again for floating point numbers + if(count($_indexes) > 0) + { + $_var_name .= implode("", $_indexes); + $_indexes = array(); + } + $_output = $_var_name; + } else { + $_output = "\$this->_tpl_vars['$_var_name']"; + } + + foreach ($_indexes as $_index) { + if (substr($_index, 0, 1) == '[') { + $_index = substr($_index, 1, -1); + if (is_numeric($_index)) { + $_output .= "[$_index]"; + } elseif (substr($_index, 0, 1) == '$') { + if (strpos($_index, '.') !== false) { + $_output .= '[' . $this->_parse_var($_index) . ']'; + } else { + $_output .= "[\$this->_tpl_vars['" . substr($_index, 1) . "']]"; + } + } else { + $_var_parts = explode('.', $_index); + $_var_section = $_var_parts[0]; + $_var_section_prop = isset($_var_parts[1]) ? $_var_parts[1] : 'index'; + $_output .= "[\$this->_sections['$_var_section']['$_var_section_prop']]"; + } + } else if (substr($_index, 0, 1) == '.') { + if (substr($_index, 1, 1) == '$') + $_output .= "[\$this->_tpl_vars['" . substr($_index, 2) . "']]"; + else + $_output .= "['" . substr($_index, 1) . "']"; + } else if (substr($_index,0,2) == '->') { + if(substr($_index,2,2) == '__') { + $this->_syntax_error('call to internal object members is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } elseif($this->security && substr($_index, 2, 1) == '_') { + $this->_syntax_error('(secure) call to private object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } elseif (substr($_index, 2, 1) == '$') { + if ($this->security) { + $this->_syntax_error('(secure) call to dynamic object member is not allowed', E_USER_ERROR, __FILE__, __LINE__); + } else { + $_output .= '->{(($_var=$this->_tpl_vars[\''.substr($_index,3).'\']) && substr($_var,0,2)!=\'__\') ? $_var : $this->trigger_error("cannot access property \\"$_var\\"")}'; + } + } else { + $_output .= $_index; + } + } elseif (substr($_index, 0, 1) == '(') { + $_index = $this->_parse_parenth_args($_index); + $_output .= $_index; + } else { + $_output .= $_index; + } + } + } + + return $_output; + } + + /** + * parse arguments in function call parenthesis + * + * @param string $parenth_args + * @return string + */ + function _parse_parenth_args($parenth_args) + { + preg_match_all('~' . $this->_param_regexp . '~',$parenth_args, $match); + $orig_vals = $match = $match[0]; + $this->_parse_vars_props($match); + $replace = array(); + for ($i = 0, $count = count($match); $i < $count; $i++) { + $replace[$orig_vals[$i]] = $match[$i]; + } + return strtr($parenth_args, $replace); + } + + /** + * parse configuration variable expression into PHP code + * + * @param string $conf_var_expr + */ + function _parse_conf_var($conf_var_expr) + { + $parts = explode('|', $conf_var_expr, 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; + + $var_name = substr($var_ref, 1, -1); + + $output = "\$this->_config[0]['vars']['$var_name']"; + + $this->_parse_modifiers($output, $modifiers); + + return $output; + } + + /** + * parse section property expression into PHP code + * + * @param string $section_prop_expr + * @return string + */ + function _parse_section_prop($section_prop_expr) + { + $parts = explode('|', $section_prop_expr, 2); + $var_ref = $parts[0]; + $modifiers = isset($parts[1]) ? $parts[1] : ''; + + preg_match('!%(\w+)\.(\w+)%!', $var_ref, $match); + $section_name = $match[1]; + $prop_name = $match[2]; + + $output = "\$this->_sections['$section_name']['$prop_name']"; + + $this->_parse_modifiers($output, $modifiers); + + return $output; + } + + + /** + * parse modifier chain into PHP code + * + * sets $output to parsed modified chain + * @param string $output + * @param string $modifier_string + */ + function _parse_modifiers(&$output, $modifier_string) + { + preg_match_all('~\|(@?\w+)((?>:(?:'. $this->_qstr_regexp . '|[^|]+))*)~', '|' . $modifier_string, $_match); + list(, $_modifiers, $modifier_arg_strings) = $_match; + + for ($_i = 0, $_for_max = count($_modifiers); $_i < $_for_max; $_i++) { + $_modifier_name = $_modifiers[$_i]; + + if($_modifier_name == 'smarty') { + // skip smarty modifier + continue; + } + + preg_match_all('~:(' . $this->_qstr_regexp . '|[^:]+)~', $modifier_arg_strings[$_i], $_match); + $_modifier_args = $_match[1]; + + if (substr($_modifier_name, 0, 1) == '@') { + $_map_array = false; + $_modifier_name = substr($_modifier_name, 1); + } else { + $_map_array = true; + } + + if (empty($this->_plugins['modifier'][$_modifier_name]) + && !$this->_get_plugin_filepath('modifier', $_modifier_name) + && function_exists($_modifier_name)) { + if ($this->security && !in_array($_modifier_name, $this->security_settings['MODIFIER_FUNCS'])) { + $this->_trigger_fatal_error("[plugin] (secure mode) modifier '$_modifier_name' is not allowed" , $this->_current_file, $this->_current_line_no, __FILE__, __LINE__); + } else { + $this->_plugins['modifier'][$_modifier_name] = array($_modifier_name, null, null, false); + } + } + $this->_add_plugin('modifier', $_modifier_name); + + $this->_parse_vars_props($_modifier_args); + + if($_modifier_name == 'default') { + // supress notifications of default modifier vars and args + if(substr($output, 0, 1) == '$') { + $output = '@' . $output; + } + if(isset($_modifier_args[0]) && substr($_modifier_args[0], 0, 1) == '$') { + $_modifier_args[0] = '@' . $_modifier_args[0]; + } + } + if (count($_modifier_args) > 0) + $_modifier_args = ', '.implode(', ', $_modifier_args); + else + $_modifier_args = ''; + + if ($_map_array) { + $output = "((is_array(\$_tmp=$output)) ? \$this->_run_mod_handler('$_modifier_name', true, \$_tmp$_modifier_args) : " . $this->_compile_plugin_call('modifier', $_modifier_name) . "(\$_tmp$_modifier_args))"; + + } else { + + $output = $this->_compile_plugin_call('modifier', $_modifier_name)."($output$_modifier_args)"; + + } + } + } + + + /** + * add plugin + * + * @param string $type + * @param string $name + * @param boolean? $delayed_loading + */ + function _add_plugin($type, $name, $delayed_loading = null) + { + if (!isset($this->_plugin_info[$type])) { + $this->_plugin_info[$type] = array(); + } + if (!isset($this->_plugin_info[$type][$name])) { + $this->_plugin_info[$type][$name] = array($this->_current_file, + $this->_current_line_no, + $delayed_loading); + } + } + + + /** + * Compiles references of type $smarty.foo + * + * @param string $indexes + * @return string + */ + function _compile_smarty_ref(&$indexes) + { + /* Extract the reference name. */ + $_ref = substr($indexes[0], 1); + foreach($indexes as $_index_no=>$_index) { + if (substr($_index, 0, 1) != '.' && $_index_no<2 || !preg_match('~^(\.|\[|->)~', $_index)) { + $this->_syntax_error('$smarty' . implode('', array_slice($indexes, 0, 2)) . ' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); + } + } + + switch ($_ref) { + case 'now': + $compiled_ref = 'time()'; + $_max_index = 1; + break; + + case 'foreach': + array_shift($indexes); + $_var = $this->_parse_var_props(substr($indexes[0], 1)); + $_propname = substr($indexes[1], 1); + $_max_index = 1; + switch ($_propname) { + case 'index': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration']-1)"; + break; + + case 'first': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration'] <= 1)"; + break; + + case 'last': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['iteration'] == \$this->_foreach[$_var]['total'])"; + break; + + case 'show': + array_shift($indexes); + $compiled_ref = "(\$this->_foreach[$_var]['total'] > 0)"; + break; + + default: + unset($_max_index); + $compiled_ref = "\$this->_foreach[$_var]"; + } + break; + + case 'section': + array_shift($indexes); + $_var = $this->_parse_var_props(substr($indexes[0], 1)); + $compiled_ref = "\$this->_sections[$_var]"; + break; + + case 'get': + $compiled_ref = ($this->request_use_auto_globals) ? '$_GET' : "\$GLOBALS['HTTP_GET_VARS']"; + break; + + case 'post': + $compiled_ref = ($this->request_use_auto_globals) ? '$_POST' : "\$GLOBALS['HTTP_POST_VARS']"; + break; + + case 'cookies': + $compiled_ref = ($this->request_use_auto_globals) ? '$_COOKIE' : "\$GLOBALS['HTTP_COOKIE_VARS']"; + break; + + case 'env': + $compiled_ref = ($this->request_use_auto_globals) ? '$_ENV' : "\$GLOBALS['HTTP_ENV_VARS']"; + break; + + case 'server': + $compiled_ref = ($this->request_use_auto_globals) ? '$_SERVER' : "\$GLOBALS['HTTP_SERVER_VARS']"; + break; + + case 'session': + $compiled_ref = ($this->request_use_auto_globals) ? '$_SESSION' : "\$GLOBALS['HTTP_SESSION_VARS']"; + break; + + /* + * These cases are handled either at run-time or elsewhere in the + * compiler. + */ + case 'request': + if ($this->request_use_auto_globals) { + $compiled_ref = '$_REQUEST'; + break; + } else { + $this->_init_smarty_vars = true; + } + return null; + + case 'capture': + return null; + + case 'template': + $compiled_ref = "'$this->_current_file'"; + $_max_index = 1; + break; + + case 'version': + $compiled_ref = "'$this->_version'"; + $_max_index = 1; + break; + + case 'const': + if ($this->security && !$this->security_settings['ALLOW_CONSTANTS']) { + $this->_syntax_error("(secure mode) constants not permitted", + E_USER_WARNING, __FILE__, __LINE__); + return; + } + array_shift($indexes); + if (preg_match('!^\.\w+$!', $indexes[0])) { + $compiled_ref = '@' . substr($indexes[0], 1); + } else { + $_val = $this->_parse_var_props(substr($indexes[0], 1)); + $compiled_ref = '@constant(' . $_val . ')'; + } + $_max_index = 1; + break; + + case 'config': + $compiled_ref = "\$this->_config[0]['vars']"; + $_max_index = 3; + break; + + case 'ldelim': + $compiled_ref = "'$this->left_delimiter'"; + break; + + case 'rdelim': + $compiled_ref = "'$this->right_delimiter'"; + break; + + default: + $this->_syntax_error('$smarty.' . $_ref . ' is an unknown reference', E_USER_ERROR, __FILE__, __LINE__); + break; + } + + if (isset($_max_index) && count($indexes) > $_max_index) { + $this->_syntax_error('$smarty' . implode('', $indexes) .' is an invalid reference', E_USER_ERROR, __FILE__, __LINE__); + } + + array_shift($indexes); + return $compiled_ref; + } + + /** + * compiles call to plugin of type $type with name $name + * returns a string containing the function-name or method call + * without the paramter-list that would have follow to make the + * call valid php-syntax + * + * @param string $type + * @param string $name + * @return string + */ + function _compile_plugin_call($type, $name) { + if (isset($this->_plugins[$type][$name])) { + /* plugin loaded */ + if (is_array($this->_plugins[$type][$name][0])) { + return ((is_object($this->_plugins[$type][$name][0][0])) ? + "\$this->_plugins['$type']['$name'][0][0]->" /* method callback */ + : (string)($this->_plugins[$type][$name][0][0]).'::' /* class callback */ + ). $this->_plugins[$type][$name][0][1]; + + } else { + /* function callback */ + return $this->_plugins[$type][$name][0]; + + } + } else { + /* plugin not loaded -> auto-loadable-plugin */ + return 'smarty_'.$type.'_'.$name; + + } + } + + /** + * load pre- and post-filters + */ + function _load_filters() + { + if (count($this->_plugins['prefilter']) > 0) { + foreach ($this->_plugins['prefilter'] as $filter_name => $prefilter) { + if ($prefilter === false) { + unset($this->_plugins['prefilter'][$filter_name]); + $_params = array('plugins' => array(array('prefilter', $filter_name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + } + } + } + if (count($this->_plugins['postfilter']) > 0) { + foreach ($this->_plugins['postfilter'] as $filter_name => $postfilter) { + if ($postfilter === false) { + unset($this->_plugins['postfilter'][$filter_name]); + $_params = array('plugins' => array(array('postfilter', $filter_name, null, null, false))); + require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); + smarty_core_load_plugins($_params, $this); + } + } + } + } + + + /** + * Quote subpattern references + * + * @param string $string + * @return string + */ + function _quote_replace($string) + { + return strtr($string, array('\\' => '\\\\', '$' => '\\$')); + } + + /** + * display Smarty syntax error + * + * @param string $error_msg + * @param integer $error_type + * @param string $file + * @param integer $line + */ + function _syntax_error($error_msg, $error_type = E_USER_ERROR, $file=null, $line=null) + { + $this->_trigger_fatal_error("syntax error: $error_msg", $this->_current_file, $this->_current_line_no, $file, $line, $error_type); + } + + + /** + * check if the compilation changes from cacheable to + * non-cacheable state with the beginning of the current + * plugin. return php-code to reflect the transition. + * @return string + */ + function _push_cacheable_state($type, $name) { + $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; + if ($_cacheable + || 0<$this->_cacheable_state++) return ''; + if (!isset($this->_cache_serial)) $this->_cache_serial = md5(uniqid('Smarty')); + $_ret = 'if ($this->caching && !$this->_cache_including): echo \'{nocache:' + . $this->_cache_serial . '#' . $this->_nocache_count + . '}\'; endif;'; + return $_ret; + } + + + /** + * check if the compilation changes from non-cacheable to + * cacheable state with the end of the current plugin return + * php-code to reflect the transition. + * @return string + */ + function _pop_cacheable_state($type, $name) { + $_cacheable = !isset($this->_plugins[$type][$name]) || $this->_plugins[$type][$name][4]; + if ($_cacheable + || --$this->_cacheable_state>0) return ''; + return 'if ($this->caching && !$this->_cache_including): echo \'{/nocache:' + . $this->_cache_serial . '#' . ($this->_nocache_count++) + . '}\'; endif;'; + } + + + /** + * push opening tag-name, file-name and line-number on the tag-stack + * @param string the opening tag's name + */ + function _push_tag($open_tag) + { + array_push($this->_tag_stack, array($open_tag, $this->_current_line_no)); + } + + /** + * pop closing tag-name + * raise an error if this stack-top doesn't match with the closing tag + * @param string the closing tag's name + * @return string the opening tag's name + */ + function _pop_tag($close_tag) + { + $message = ''; + if (count($this->_tag_stack)>0) { + list($_open_tag, $_line_no) = array_pop($this->_tag_stack); + if ($close_tag == $_open_tag) { + return $_open_tag; + } + if ($close_tag == 'if' && ($_open_tag == 'else' || $_open_tag == 'elseif' )) { + return $this->_pop_tag($close_tag); + } + if ($close_tag == 'section' && $_open_tag == 'sectionelse') { + $this->_pop_tag($close_tag); + return $_open_tag; + } + if ($close_tag == 'foreach' && $_open_tag == 'foreachelse') { + $this->_pop_tag($close_tag); + return $_open_tag; + } + if ($_open_tag == 'else' || $_open_tag == 'elseif') { + $_open_tag = 'if'; + } elseif ($_open_tag == 'sectionelse') { + $_open_tag = 'section'; + } elseif ($_open_tag == 'foreachelse') { + $_open_tag = 'foreach'; + } + $message = " expected {/$_open_tag} (opened line $_line_no)."; + } + $this->_syntax_error("mismatched tag {/$close_tag}.$message", + E_USER_ERROR, __FILE__, __LINE__); + } + +} + +/** + * compare to values by their string length + * + * @access private + * @param string $a + * @param string $b + * @return 0|-1|1 + */ +function _smarty_sort_length($a, $b) +{ + if($a == $b) + return 0; + + if(strlen($a) == strlen($b)) + return ($a > $b) ? -1 : 1; + + return (strlen($a) > strlen($b)) ? -1 : 1; +} + + +/* vim: set et: */ + +?> diff --git a/BSF/include/smarty/libs/debug.tpl b/BSF/include/smarty/libs/debug.tpl new file mode 100644 index 000000000..c05ef5d0b --- /dev/null +++ b/BSF/include/smarty/libs/debug.tpl @@ -0,0 +1,157 @@ +{* Smarty *} +{* debug.tpl, last updated version 2.1.0 *} +{assign_debug_info} +{capture assign=debug_output} +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +<head> + <title>Smarty Debug Console</title> +{literal} +<style type="text/css"> +/* <![CDATA[ */ +body, h1, h2, td, th, p { + font-family: sans-serif; + font-weight: normal; + font-size: 0.9em; + margin: 1px; + padding: 0; +} + +h1 { + margin: 0; + text-align: left; + padding: 2px; + background-color: #f0c040; + color: black; + font-weight: bold; + font-size: 1.2em; + } + +h2 { + background-color: #9B410E; + color: white; + text-align: left; + font-weight: bold; + padding: 2px; + border-top: 1px solid black; +} + +body { + background: black; +} + +p, table, div { + background: #f0ead8; +} + +p { + margin: 0; + font-style: italic; + text-align: center; +} + +table { + width: 100%; +} + +th, td { + font-family: monospace; + vertical-align: top; + text-align: left; + width: 50%; +} + +td { + color: green; +} + +.odd { + background-color: #eeeeee; +} + +.even { + background-color: #fafafa; +} + +.exectime { + font-size: 0.8em; + font-style: italic; +} + +#table_assigned_vars th { + color: blue; +} + +#table_config_vars th { + color: maroon; +} +/* ]]> */ +</style> +{/literal} +</head> +<body> + +<h1>Smarty Debug Console</h1> + +<h2>included templates & config files (load time in seconds)</h2> + +<div> +{section name=templates loop=$_debug_tpls} + {section name=indent loop=$_debug_tpls[templates].depth} {/section} + <font color={if $_debug_tpls[templates].type eq "template"}brown{elseif $_debug_tpls[templates].type eq "insert"}black{else}green{/if}> + {$_debug_tpls[templates].filename|escape:html}</font> + {if isset($_debug_tpls[templates].exec_time)} + <span class="exectime"> + ({$_debug_tpls[templates].exec_time|string_format:"%.5f"}) + {if %templates.index% eq 0}(total){/if} + </span> + {/if} + <br /> +{sectionelse} + <p>no templates included</p> +{/section} +</div> + +<h2>assigned template variables</h2> + +<table id="table_assigned_vars"> + {section name=vars loop=$_debug_keys} + <tr class="{cycle values="odd,even"}"> + <th>{ldelim}${$_debug_keys[vars]|escape:'html'}{rdelim}</th> + <td>{$_debug_vals[vars]|@debug_print_var}</td></tr> + {sectionelse} + <tr><td><p>no template variables assigned</p></td></tr> + {/section} +</table> + +<h2>assigned config file variables (outer template scope)</h2> + +<table id="table_config_vars"> + {section name=config_vars loop=$_debug_config_keys} + <tr class="{cycle values="odd,even"}"> + <th>{ldelim}#{$_debug_config_keys[config_vars]|escape:'html'}#{rdelim}</th> + <td>{$_debug_config_vals[config_vars]|@debug_print_var}</td></tr> + {sectionelse} + <tr><td><p>no config vars assigned</p></td></tr> + {/section} +</table> +</body> +</html> +{/capture} +{if isset($_smarty_debug_output) and $_smarty_debug_output eq "html"} + {$debug_output} +{else} +<script type="text/javascript"> +// <![CDATA[ + if ( self.name == '' ) {ldelim} + var title = 'Console'; + {rdelim} + else {ldelim} + var title = 'Console_' + self.name; + {rdelim} + _smarty_console = window.open("",title.value,"width=680,height=600,resizable,scrollbars=yes"); + _smarty_console.document.write('{$debug_output|escape:'javascript'}'); + _smarty_console.document.close(); +// ]]> +</script> +{/if}
\ No newline at end of file diff --git a/BSF/include/smarty/libs/internals/core.assemble_plugin_filepath.php b/BSF/include/smarty/libs/internals/core.assemble_plugin_filepath.php new file mode 100644 index 000000000..690d3ddbc --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.assemble_plugin_filepath.php @@ -0,0 +1,67 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * assemble filepath of requested plugin + * + * @param string $type + * @param string $name + * @return string|false + */ +function smarty_core_assemble_plugin_filepath($params, &$smarty) +{ + static $_filepaths_cache = array(); + + $_plugin_filename = $params['type'] . '.' . $params['name'] . '.php'; + if (isset($_filepaths_cache[$_plugin_filename])) { + return $_filepaths_cache[$_plugin_filename]; + } + $_return = false; + + foreach ((array)$smarty->plugins_dir as $_plugin_dir) { + + $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename; + + // see if path is relative + if (!preg_match("/^([\/\\\\]|[a-zA-Z]:[\/\\\\])/", $_plugin_dir)) { + $_relative_paths[] = $_plugin_dir; + // relative path, see if it is in the SMARTY_DIR + if (@is_readable(SMARTY_DIR . $_plugin_filepath)) { + $_return = SMARTY_DIR . $_plugin_filepath; + break; + } + } + // try relative to cwd (or absolute) + if (@is_readable($_plugin_filepath)) { + $_return = $_plugin_filepath; + break; + } + } + + if($_return === false) { + // still not found, try PHP include_path + if(isset($_relative_paths)) { + foreach ((array)$_relative_paths as $_plugin_dir) { + + $_plugin_filepath = $_plugin_dir . DIRECTORY_SEPARATOR . $_plugin_filename; + + $_params = array('file_path' => $_plugin_filepath); + require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $smarty)) { + $_return = $_params['new_file_path']; + break; + } + } + } + } + $_filepaths_cache[$_plugin_filename] = $_return; + return $_return; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.assign_smarty_interface.php b/BSF/include/smarty/libs/internals/core.assign_smarty_interface.php new file mode 100644 index 000000000..7e65a73ec --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.assign_smarty_interface.php @@ -0,0 +1,43 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Smarty assign_smarty_interface core plugin + * + * Type: core<br> + * Name: assign_smarty_interface<br> + * Purpose: assign the $smarty interface variable + * @param array Format: null + * @param Smarty + */ +function smarty_core_assign_smarty_interface($params, &$smarty) +{ + if (isset($smarty->_smarty_vars) && isset($smarty->_smarty_vars['request'])) { + return; + } + + $_globals_map = array('g' => 'HTTP_GET_VARS', + 'p' => 'HTTP_POST_VARS', + 'c' => 'HTTP_COOKIE_VARS', + 's' => 'HTTP_SERVER_VARS', + 'e' => 'HTTP_ENV_VARS'); + + $_smarty_vars_request = array(); + + foreach (preg_split('!!', strtolower($smarty->request_vars_order)) as $_c) { + if (isset($_globals_map[$_c])) { + $_smarty_vars_request = array_merge($_smarty_vars_request, $GLOBALS[$_globals_map[$_c]]); + } + } + $_smarty_vars_request = @array_merge($_smarty_vars_request, $GLOBALS['HTTP_SESSION_VARS']); + + $smarty->_smarty_vars['request'] = $_smarty_vars_request; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.create_dir_structure.php b/BSF/include/smarty/libs/internals/core.create_dir_structure.php new file mode 100644 index 000000000..3eecc4972 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.create_dir_structure.php @@ -0,0 +1,79 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * create full directory structure + * + * @param string $dir + */ + +// $dir + +function smarty_core_create_dir_structure($params, &$smarty) +{ + if (!file_exists($params['dir'])) { + $_open_basedir_ini = ini_get('open_basedir'); + + if (DIRECTORY_SEPARATOR=='/') { + /* unix-style paths */ + $_dir = $params['dir']; + $_dir_parts = preg_split('!/+!', $_dir, -1, PREG_SPLIT_NO_EMPTY); + $_new_dir = (substr($_dir, 0, 1)=='/') ? '/' : getcwd().'/'; + if($_use_open_basedir = !empty($_open_basedir_ini)) { + $_open_basedirs = explode(':', $_open_basedir_ini); + } + + } else { + /* other-style paths */ + $_dir = str_replace('\\','/', $params['dir']); + $_dir_parts = preg_split('!/+!', $_dir, -1, PREG_SPLIT_NO_EMPTY); + if (preg_match('!^((//)|([a-zA-Z]:/))!', $_dir, $_root_dir)) { + /* leading "//" for network volume, or "[letter]:/" for full path */ + $_new_dir = $_root_dir[1]; + /* remove drive-letter from _dir_parts */ + if (isset($_root_dir[3])) array_shift($_dir_parts); + + } else { + $_new_dir = str_replace('\\', '/', getcwd()).'/'; + + } + + if($_use_open_basedir = !empty($_open_basedir_ini)) { + $_open_basedirs = explode(';', str_replace('\\', '/', $_open_basedir_ini)); + } + + } + + /* all paths use "/" only from here */ + foreach ($_dir_parts as $_dir_part) { + $_new_dir .= $_dir_part; + + if ($_use_open_basedir) { + // do not attempt to test or make directories outside of open_basedir + $_make_new_dir = false; + foreach ($_open_basedirs as $_open_basedir) { + if (substr($_new_dir, 0, strlen($_open_basedir)) == $_open_basedir) { + $_make_new_dir = true; + break; + } + } + } else { + $_make_new_dir = true; + } + + if ($_make_new_dir && !file_exists($_new_dir) && !@mkdir($_new_dir, $smarty->_dir_perms) && !is_dir($_new_dir)) { + $smarty->trigger_error("problem creating directory '" . $_new_dir . "'"); + return false; + } + $_new_dir .= '/'; + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.display_debug_console.php b/BSF/include/smarty/libs/internals/core.display_debug_console.php new file mode 100644 index 000000000..1a80f3909 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.display_debug_console.php @@ -0,0 +1,61 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Smarty debug_console function plugin + * + * Type: core<br> + * Name: display_debug_console<br> + * Purpose: display the javascript debug console window + * @param array Format: null + * @param Smarty + */ +function smarty_core_display_debug_console($params, &$smarty) +{ + // we must force compile the debug template in case the environment + // changed between separate applications. + + if(empty($smarty->debug_tpl)) { + // set path to debug template from SMARTY_DIR + $smarty->debug_tpl = SMARTY_DIR . 'debug.tpl'; + if($smarty->security && is_file($smarty->debug_tpl)) { + $smarty->secure_dir[] = realpath($smarty->debug_tpl); + } + $smarty->debug_tpl = 'file:' . SMARTY_DIR . 'debug.tpl'; + } + + $_ldelim_orig = $smarty->left_delimiter; + $_rdelim_orig = $smarty->right_delimiter; + + $smarty->left_delimiter = '{'; + $smarty->right_delimiter = '}'; + + $_compile_id_orig = $smarty->_compile_id; + $smarty->_compile_id = null; + + $_compile_path = $smarty->_get_compile_path($smarty->debug_tpl); + if ($smarty->_compile_resource($smarty->debug_tpl, $_compile_path)) + { + ob_start(); + $smarty->_include($_compile_path); + $_results = ob_get_contents(); + ob_end_clean(); + } else { + $_results = ''; + } + + $smarty->_compile_id = $_compile_id_orig; + + $smarty->left_delimiter = $_ldelim_orig; + $smarty->right_delimiter = $_rdelim_orig; + + return $_results; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.get_include_path.php b/BSF/include/smarty/libs/internals/core.get_include_path.php new file mode 100644 index 000000000..43432412b --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.get_include_path.php @@ -0,0 +1,44 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Get path to file from include_path + * + * @param string $file_path + * @param string $new_file_path + * @return boolean + * @staticvar array|null + */ + +// $file_path, &$new_file_path + +function smarty_core_get_include_path(&$params, &$smarty) +{ + static $_path_array = null; + + if(!isset($_path_array)) { + $_ini_include_path = ini_get('include_path'); + + if(strstr($_ini_include_path,';')) { + // windows pathnames + $_path_array = explode(';',$_ini_include_path); + } else { + $_path_array = explode(':',$_ini_include_path); + } + } + foreach ($_path_array as $_include_path) { + if (@is_readable($_include_path . DIRECTORY_SEPARATOR . $params['file_path'])) { + $params['new_file_path'] = $_include_path . DIRECTORY_SEPARATOR . $params['file_path']; + return true; + } + } + return false; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.get_microtime.php b/BSF/include/smarty/libs/internals/core.get_microtime.php new file mode 100644 index 000000000..f1a28e042 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.get_microtime.php @@ -0,0 +1,23 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Get seconds and microseconds + * @return double + */ +function smarty_core_get_microtime($params, &$smarty) +{ + $mtime = microtime(); + $mtime = explode(" ", $mtime); + $mtime = (double)($mtime[1]) + (double)($mtime[0]); + return ($mtime); +} + + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.get_php_resource.php b/BSF/include/smarty/libs/internals/core.get_php_resource.php new file mode 100644 index 000000000..786d4e78e --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.get_php_resource.php @@ -0,0 +1,80 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Retrieves PHP script resource + * + * sets $php_resource to the returned resource + * @param string $resource + * @param string $resource_type + * @param $php_resource + * @return boolean + */ + +function smarty_core_get_php_resource(&$params, &$smarty) +{ + + $params['resource_base_path'] = $smarty->trusted_dir; + $smarty->_parse_resource_name($params, $smarty); + + /* + * Find out if the resource exists. + */ + + if ($params['resource_type'] == 'file') { + $_readable = false; + if(file_exists($params['resource_name']) && is_readable($params['resource_name'])) { + $_readable = true; + } else { + // test for file in include_path + $_params = array('file_path' => $params['resource_name']); + require_once(SMARTY_CORE_DIR . 'core.get_include_path.php'); + if(smarty_core_get_include_path($_params, $smarty)) { + $_include_path = $_params['new_file_path']; + $_readable = true; + } + } + } else if ($params['resource_type'] != 'file') { + $_template_source = null; + $_readable = is_callable($smarty->_plugins['resource'][$params['resource_type']][0][0]) + && call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][0], + array($params['resource_name'], &$_template_source, &$smarty)); + } + + /* + * Set the error function, depending on which class calls us. + */ + if (method_exists($smarty, '_syntax_error')) { + $_error_funcc = '_syntax_error'; + } else { + $_error_funcc = 'trigger_error'; + } + + if ($_readable) { + if ($smarty->security) { + require_once(SMARTY_CORE_DIR . 'core.is_trusted.php'); + if (!smarty_core_is_trusted($params, $smarty)) { + $smarty->$_error_funcc('(secure mode) ' . $params['resource_type'] . ':' . $params['resource_name'] . ' is not trusted'); + return false; + } + } + } else { + $smarty->$_error_funcc($params['resource_type'] . ':' . $params['resource_name'] . ' is not readable'); + return false; + } + + if ($params['resource_type'] == 'file') { + $params['php_resource'] = $params['resource_name']; + } else { + $params['php_resource'] = $_template_source; + } + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.is_secure.php b/BSF/include/smarty/libs/internals/core.is_secure.php new file mode 100644 index 000000000..d54abd432 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.is_secure.php @@ -0,0 +1,59 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * determines if a resource is secure or not. + * + * @param string $resource_type + * @param string $resource_name + * @return boolean + */ + +// $resource_type, $resource_name + +function smarty_core_is_secure($params, &$smarty) +{ + if (!$smarty->security || $smarty->security_settings['INCLUDE_ANY']) { + return true; + } + + if ($params['resource_type'] == 'file') { + $_rp = realpath($params['resource_name']); + if (isset($params['resource_base_path'])) { + foreach ((array)$params['resource_base_path'] as $curr_dir) { + if ( ($_cd = realpath($curr_dir)) !== false && + strncmp($_rp, $_cd, strlen($_cd)) == 0 && + substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR ) { + return true; + } + } + } + if (!empty($smarty->secure_dir)) { + foreach ((array)$smarty->secure_dir as $curr_dir) { + if ( ($_cd = realpath($curr_dir)) !== false) { + if($_cd == $_rp) { + return true; + } elseif (strncmp($_rp, $_cd, strlen($_cd)) == 0 && + substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR) { + return true; + } + } + } + } + } else { + // resource is not on local file system + return call_user_func_array( + $smarty->_plugins['resource'][$params['resource_type']][0][2], + array($params['resource_name'], &$smarty)); + } + + return false; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.is_trusted.php b/BSF/include/smarty/libs/internals/core.is_trusted.php new file mode 100644 index 000000000..429973158 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.is_trusted.php @@ -0,0 +1,47 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * determines if a resource is trusted or not + * + * @param string $resource_type + * @param string $resource_name + * @return boolean + */ + + // $resource_type, $resource_name + +function smarty_core_is_trusted($params, &$smarty) +{ + $_smarty_trusted = false; + if ($params['resource_type'] == 'file') { + if (!empty($smarty->trusted_dir)) { + $_rp = realpath($params['resource_name']); + foreach ((array)$smarty->trusted_dir as $curr_dir) { + if (!empty($curr_dir) && is_readable ($curr_dir)) { + $_cd = realpath($curr_dir); + if (strncmp($_rp, $_cd, strlen($_cd)) == 0 + && substr($_rp, strlen($_cd), 1) == DIRECTORY_SEPARATOR ) { + $_smarty_trusted = true; + break; + } + } + } + } + + } else { + // resource is not on local file system + $_smarty_trusted = call_user_func_array($smarty->_plugins['resource'][$params['resource_type']][0][3], + array($params['resource_name'], $smarty)); + } + + return $_smarty_trusted; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.load_plugins.php b/BSF/include/smarty/libs/internals/core.load_plugins.php new file mode 100644 index 000000000..6db1dc51d --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.load_plugins.php @@ -0,0 +1,125 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Load requested plugins + * + * @param array $plugins + */ + +// $plugins + +function smarty_core_load_plugins($params, &$smarty) +{ + + foreach ($params['plugins'] as $_plugin_info) { + list($_type, $_name, $_tpl_file, $_tpl_line, $_delayed_loading) = $_plugin_info; + $_plugin = &$smarty->_plugins[$_type][$_name]; + + /* + * We do not load plugin more than once for each instance of Smarty. + * The following code checks for that. The plugin can also be + * registered dynamically at runtime, in which case template file + * and line number will be unknown, so we fill them in. + * + * The final element of the info array is a flag that indicates + * whether the dynamically registered plugin function has been + * checked for existence yet or not. + */ + if (isset($_plugin)) { + if (empty($_plugin[3])) { + if (!is_callable($_plugin[0])) { + $smarty->_trigger_fatal_error("[plugin] $_type '$_name' is not implemented", $_tpl_file, $_tpl_line, __FILE__, __LINE__); + } else { + $_plugin[1] = $_tpl_file; + $_plugin[2] = $_tpl_line; + $_plugin[3] = true; + if (!isset($_plugin[4])) $_plugin[4] = true; /* cacheable */ + } + } + continue; + } else if ($_type == 'insert') { + /* + * For backwards compatibility, we check for insert functions in + * the symbol table before trying to load them as a plugin. + */ + $_plugin_func = 'insert_' . $_name; + if (function_exists($_plugin_func)) { + $_plugin = array($_plugin_func, $_tpl_file, $_tpl_line, true, false); + continue; + } + } + + $_plugin_file = $smarty->_get_plugin_filepath($_type, $_name); + + if (! $_found = ($_plugin_file != false)) { + $_message = "could not load plugin file '$_type.$_name.php'\n"; + } + + /* + * If plugin file is found, it -must- provide the properly named + * plugin function. In case it doesn't, simply output the error and + * do not fall back on any other method. + */ + if ($_found) { + include_once $_plugin_file; + + $_plugin_func = 'smarty_' . $_type . '_' . $_name; + if (!function_exists($_plugin_func)) { + $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", $_tpl_file, $_tpl_line, __FILE__, __LINE__); + continue; + } + } + /* + * In case of insert plugins, their code may be loaded later via + * 'script' attribute. + */ + else if ($_type == 'insert' && $_delayed_loading) { + $_plugin_func = 'smarty_' . $_type . '_' . $_name; + $_found = true; + } + + /* + * Plugin specific processing and error checking. + */ + if (!$_found) { + if ($_type == 'modifier') { + /* + * In case modifier falls back on using PHP functions + * directly, we only allow those specified in the security + * context. + */ + if ($smarty->security && !in_array($_name, $smarty->security_settings['MODIFIER_FUNCS'])) { + $_message = "(secure mode) modifier '$_name' is not allowed"; + } else { + if (!function_exists($_name)) { + $_message = "modifier '$_name' is not implemented"; + } else { + $_plugin_func = $_name; + $_found = true; + } + } + } else if ($_type == 'function') { + /* + * This is a catch-all situation. + */ + $_message = "unknown tag - '$_name'"; + } + } + + if ($_found) { + $smarty->_plugins[$_type][$_name] = array($_plugin_func, $_tpl_file, $_tpl_line, true, true); + } else { + // output error + $smarty->_trigger_fatal_error('[plugin] ' . $_message, $_tpl_file, $_tpl_line, __FILE__, __LINE__); + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.load_resource_plugin.php b/BSF/include/smarty/libs/internals/core.load_resource_plugin.php new file mode 100644 index 000000000..a7d37d1af --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.load_resource_plugin.php @@ -0,0 +1,74 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * load a resource plugin + * + * @param string $type + */ + +// $type + +function smarty_core_load_resource_plugin($params, &$smarty) +{ + /* + * Resource plugins are not quite like the other ones, so they are + * handled differently. The first element of plugin info is the array of + * functions provided by the plugin, the second one indicates whether + * all of them exist or not. + */ + + $_plugin = &$smarty->_plugins['resource'][$params['type']]; + if (isset($_plugin)) { + if (!$_plugin[1] && count($_plugin[0])) { + $_plugin[1] = true; + foreach ($_plugin[0] as $_plugin_func) { + if (!is_callable($_plugin_func)) { + $_plugin[1] = false; + break; + } + } + } + + if (!$_plugin[1]) { + $smarty->_trigger_fatal_error("[plugin] resource '" . $params['type'] . "' is not implemented", null, null, __FILE__, __LINE__); + } + + return; + } + + $_plugin_file = $smarty->_get_plugin_filepath('resource', $params['type']); + $_found = ($_plugin_file != false); + + if ($_found) { /* + * If the plugin file is found, it -must- provide the properly named + * plugin functions. + */ + include_once($_plugin_file); + + /* + * Locate functions that we require the plugin to provide. + */ + $_resource_ops = array('source', 'timestamp', 'secure', 'trusted'); + $_resource_funcs = array(); + foreach ($_resource_ops as $_op) { + $_plugin_func = 'smarty_resource_' . $params['type'] . '_' . $_op; + if (!function_exists($_plugin_func)) { + $smarty->_trigger_fatal_error("[plugin] function $_plugin_func() not found in $_plugin_file", null, null, __FILE__, __LINE__); + return; + } else { + $_resource_funcs[] = $_plugin_func; + } + } + + $smarty->_plugins['resource'][$params['type']] = array($_resource_funcs, true); + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.process_cached_inserts.php b/BSF/include/smarty/libs/internals/core.process_cached_inserts.php new file mode 100644 index 000000000..1d78edd93 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.process_cached_inserts.php @@ -0,0 +1,71 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Replace cached inserts with the actual results + * + * @param string $results + * @return string + */ +function smarty_core_process_cached_inserts($params, &$smarty) +{ + preg_match_all('!'.$smarty->_smarty_md5.'{insert_cache (.*)}'.$smarty->_smarty_md5.'!Uis', + $params['results'], $match); + list($cached_inserts, $insert_args) = $match; + + for ($i = 0, $for_max = count($cached_inserts); $i < $for_max; $i++) { + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + $args = unserialize($insert_args[$i]); + $name = $args['name']; + + if (isset($args['script'])) { + $_params = array('resource_name' => $smarty->_dequote($args['script'])); + require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); + if(!smarty_core_get_php_resource($_params, $smarty)) { + return false; + } + $resource_type = $_params['resource_type']; + $php_resource = $_params['php_resource']; + + + if ($resource_type == 'file') { + $smarty->_include($php_resource, true); + } else { + $smarty->_eval($php_resource); + } + } + + $function_name = $smarty->_plugins['insert'][$name][0]; + if (empty($args['assign'])) { + $replace = $function_name($args, $smarty); + } else { + $smarty->assign($args['assign'], $function_name($args, $smarty)); + $replace = ''; + } + + $params['results'] = substr_replace($params['results'], $replace, strpos($params['results'], $cached_inserts[$i]), strlen($cached_inserts[$i])); + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'insert', + 'filename' => 'insert_'.$name, + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $debug_start_time); + } + } + + return $params['results']; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.process_compiled_include.php b/BSF/include/smarty/libs/internals/core.process_compiled_include.php new file mode 100644 index 000000000..d539423bf --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.process_compiled_include.php @@ -0,0 +1,37 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Replace nocache-tags by results of the corresponding non-cacheable + * functions and return it + * + * @param string $compiled_tpl + * @param string $cached_source + * @return string + */ + +function smarty_core_process_compiled_include($params, &$smarty) +{ + $_cache_including = $smarty->_cache_including; + $smarty->_cache_including = true; + + $_return = $params['results']; + + foreach ($smarty->_cache_info['cache_serials'] as $_include_file_path=>$_cache_serial) { + $smarty->_include($_include_file_path, true); + } + + foreach ($smarty->_cache_serials as $_include_file_path=>$_cache_serial) { + $_return = preg_replace_callback('!(\{nocache\:('.$_cache_serial.')#(\d+)\})!s', + array(&$smarty, '_process_compiled_include_callback'), + $_return); + } + $smarty->_cache_including = $_cache_including; + return $_return; +} + +?> diff --git a/BSF/include/smarty/libs/internals/core.read_cache_file.php b/BSF/include/smarty/libs/internals/core.read_cache_file.php new file mode 100644 index 000000000..c60e113a7 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.read_cache_file.php @@ -0,0 +1,101 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * read a cache file, determine if it needs to be + * regenerated or not + * + * @param string $tpl_file + * @param string $cache_id + * @param string $compile_id + * @param string $results + * @return boolean + */ + +// $tpl_file, $cache_id, $compile_id, &$results + +function smarty_core_read_cache_file(&$params, &$smarty) +{ + static $content_cache = array(); + + if ($smarty->force_compile) { + // force compile enabled, always regenerate + return false; + } + + if (isset($content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']])) { + list($params['results'], $smarty->_cache_info) = $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']]; + return true; + } + + if (!empty($smarty->cache_handler_func)) { + // use cache_handler function + call_user_func_array($smarty->cache_handler_func, + array('read', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null)); + } else { + // use local cache file + $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']); + $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id); + $params['results'] = $smarty->_read_file($_cache_file); + } + + if (empty($params['results'])) { + // nothing to parse (error?), regenerate cache + return false; + } + + $_contents = $params['results']; + $_info_start = strpos($_contents, "\n") + 1; + $_info_len = (int)substr($_contents, 0, $_info_start - 1); + $_cache_info = unserialize(substr($_contents, $_info_start, $_info_len)); + $params['results'] = substr($_contents, $_info_start + $_info_len); + + if ($smarty->caching == 2 && isset ($_cache_info['expires'])){ + // caching by expiration time + if ($_cache_info['expires'] > -1 && (time() > $_cache_info['expires'])) { + // cache expired, regenerate + return false; + } + } else { + // caching by lifetime + if ($smarty->cache_lifetime > -1 && (time() - $_cache_info['timestamp'] > $smarty->cache_lifetime)) { + // cache expired, regenerate + return false; + } + } + + if ($smarty->compile_check) { + $_params = array('get_source' => false, 'quiet'=>true); + foreach (array_keys($_cache_info['template']) as $_template_dep) { + $_params['resource_name'] = $_template_dep; + if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) { + // template file has changed, regenerate cache + return false; + } + } + + if (isset($_cache_info['config'])) { + $_params = array('resource_base_path' => $smarty->config_dir, 'get_source' => false, 'quiet'=>true); + foreach (array_keys($_cache_info['config']) as $_config_dep) { + $_params['resource_name'] = $_config_dep; + if (!$smarty->_fetch_resource_info($_params) || $_cache_info['timestamp'] < $_params['resource_timestamp']) { + // config file has changed, regenerate cache + return false; + } + } + } + } + + $content_cache[$params['tpl_file'].','.$params['cache_id'].','.$params['compile_id']] = array($params['results'], $_cache_info); + + $smarty->_cache_info = $_cache_info; + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.rm_auto.php b/BSF/include/smarty/libs/internals/core.rm_auto.php new file mode 100644 index 000000000..b251f6491 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.rm_auto.php @@ -0,0 +1,71 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * delete an automagically created file by name and id + * + * @param string $auto_base + * @param string $auto_source + * @param string $auto_id + * @param integer $exp_time + * @return boolean + */ + +// $auto_base, $auto_source = null, $auto_id = null, $exp_time = null + +function smarty_core_rm_auto($params, &$smarty) +{ + if (!@is_dir($params['auto_base'])) + return false; + + if(!isset($params['auto_id']) && !isset($params['auto_source'])) { + $_params = array( + 'dirname' => $params['auto_base'], + 'level' => 0, + 'exp_time' => $params['exp_time'] + ); + require_once(SMARTY_CORE_DIR . 'core.rmdir.php'); + $_res = smarty_core_rmdir($_params, $smarty); + } else { + $_tname = $smarty->_get_auto_filename($params['auto_base'], $params['auto_source'], $params['auto_id']); + + if(isset($params['auto_source'])) { + if (isset($params['extensions'])) { + $_res = false; + foreach ((array)$params['extensions'] as $_extension) + $_res |= $smarty->_unlink($_tname.$_extension, $params['exp_time']); + } else { + $_res = $smarty->_unlink($_tname, $params['exp_time']); + } + } elseif ($smarty->use_sub_dirs) { + $_params = array( + 'dirname' => $_tname, + 'level' => 1, + 'exp_time' => $params['exp_time'] + ); + require_once(SMARTY_CORE_DIR . 'core.rmdir.php'); + $_res = smarty_core_rmdir($_params, $smarty); + } else { + // remove matching file names + $_handle = opendir($params['auto_base']); + $_res = true; + while (false !== ($_filename = readdir($_handle))) { + if($_filename == '.' || $_filename == '..') { + continue; + } elseif (substr($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, 0, strlen($_tname)) == $_tname) { + $_res &= (bool)$smarty->_unlink($params['auto_base'] . DIRECTORY_SEPARATOR . $_filename, $params['exp_time']); + } + } + } + } + + return $_res; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.rmdir.php b/BSF/include/smarty/libs/internals/core.rmdir.php new file mode 100644 index 000000000..2166c44d2 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.rmdir.php @@ -0,0 +1,54 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * delete a dir recursively (level=0 -> keep root) + * WARNING: no tests, it will try to remove what you tell it! + * + * @param string $dirname + * @param integer $level + * @param integer $exp_time + * @return boolean + */ + +// $dirname, $level = 1, $exp_time = null + +function smarty_core_rmdir($params, &$smarty) +{ + if(!isset($params['level'])) { $params['level'] = 1; } + if(!isset($params['exp_time'])) { $params['exp_time'] = null; } + + if($_handle = @opendir($params['dirname'])) { + + while (false !== ($_entry = readdir($_handle))) { + if ($_entry != '.' && $_entry != '..') { + if (@is_dir($params['dirname'] . DIRECTORY_SEPARATOR . $_entry)) { + $_params = array( + 'dirname' => $params['dirname'] . DIRECTORY_SEPARATOR . $_entry, + 'level' => $params['level'] + 1, + 'exp_time' => $params['exp_time'] + ); + smarty_core_rmdir($_params, $smarty); + } + else { + $smarty->_unlink($params['dirname'] . DIRECTORY_SEPARATOR . $_entry, $params['exp_time']); + } + } + } + closedir($_handle); + } + + if ($params['level']) { + return @rmdir($params['dirname']); + } + return (bool)$_handle; + +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.run_insert_handler.php b/BSF/include/smarty/libs/internals/core.run_insert_handler.php new file mode 100644 index 000000000..71c384508 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.run_insert_handler.php @@ -0,0 +1,71 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Handle insert tags + * + * @param array $args + * @return string + */ +function smarty_core_run_insert_handler($params, &$smarty) +{ + + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + if ($smarty->debugging) { + $_params = array(); + $_debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + if ($smarty->caching) { + $_arg_string = serialize($params['args']); + $_name = $params['args']['name']; + if (!isset($smarty->_cache_info['insert_tags'][$_name])) { + $smarty->_cache_info['insert_tags'][$_name] = array('insert', + $_name, + $smarty->_plugins['insert'][$_name][1], + $smarty->_plugins['insert'][$_name][2], + !empty($params['args']['script']) ? true : false); + } + return $smarty->_smarty_md5."{insert_cache $_arg_string}".$smarty->_smarty_md5; + } else { + if (isset($params['args']['script'])) { + $_params = array('resource_name' => $smarty->_dequote($params['args']['script'])); + require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); + if(!smarty_core_get_php_resource($_params, $smarty)) { + return false; + } + + if ($_params['resource_type'] == 'file') { + $smarty->_include($_params['php_resource'], true); + } else { + $smarty->_eval($_params['php_resource']); + } + unset($params['args']['script']); + } + + $_funcname = $smarty->_plugins['insert'][$params['args']['name']][0]; + $_content = $_funcname($params['args'], $smarty); + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'insert', + 'filename' => 'insert_'.$params['args']['name'], + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); + } + + if (!empty($params['args']["assign"])) { + $smarty->assign($params['args']["assign"], $_content); + } else { + return $_content; + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.smarty_include_php.php b/BSF/include/smarty/libs/internals/core.smarty_include_php.php new file mode 100644 index 000000000..30c6e7654 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.smarty_include_php.php @@ -0,0 +1,50 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * called for included php files within templates + * + * @param string $smarty_file + * @param string $smarty_assign variable to assign the included template's + * output into + * @param boolean $smarty_once uses include_once if this is true + * @param array $smarty_include_vars associative array of vars from + * {include file="blah" var=$var} + */ + +// $file, $assign, $once, $_smarty_include_vars + +function smarty_core_smarty_include_php($params, &$smarty) +{ + $_params = array('resource_name' => $params['smarty_file']); + require_once(SMARTY_CORE_DIR . 'core.get_php_resource.php'); + smarty_core_get_php_resource($_params, $smarty); + $_smarty_resource_type = $_params['resource_type']; + $_smarty_php_resource = $_params['php_resource']; + + if (!empty($params['smarty_assign'])) { + ob_start(); + if ($_smarty_resource_type == 'file') { + $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']); + } else { + $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']); + } + $smarty->assign($params['smarty_assign'], ob_get_contents()); + ob_end_clean(); + } else { + if ($_smarty_resource_type == 'file') { + $smarty->_include($_smarty_php_resource, $params['smarty_once'], $params['smarty_include_vars']); + } else { + $smarty->_eval($_smarty_php_resource, $params['smarty_include_vars']); + } + } +} + + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.write_cache_file.php b/BSF/include/smarty/libs/internals/core.write_cache_file.php new file mode 100644 index 000000000..72f785b74 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.write_cache_file.php @@ -0,0 +1,96 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Prepend the cache information to the cache file + * and write it + * + * @param string $tpl_file + * @param string $cache_id + * @param string $compile_id + * @param string $results + * @return true|null + */ + + // $tpl_file, $cache_id, $compile_id, $results + +function smarty_core_write_cache_file($params, &$smarty) +{ + + // put timestamp in cache header + $smarty->_cache_info['timestamp'] = time(); + if ($smarty->cache_lifetime > -1){ + // expiration set + $smarty->_cache_info['expires'] = $smarty->_cache_info['timestamp'] + $smarty->cache_lifetime; + } else { + // cache will never expire + $smarty->_cache_info['expires'] = -1; + } + + // collapse nocache.../nocache-tags + if (preg_match_all('!\{(/?)nocache\:[0-9a-f]{32}#\d+\}!', $params['results'], $match, PREG_PATTERN_ORDER)) { + // remove everything between every pair of outermost noache.../nocache-tags + // and replace it by a single nocache-tag + // this new nocache-tag will be replaced by dynamic contents in + // smarty_core_process_compiled_includes() on a cache-read + + $match_count = count($match[0]); + $results = preg_split('!(\{/?nocache\:[0-9a-f]{32}#\d+\})!', $params['results'], -1, PREG_SPLIT_DELIM_CAPTURE); + + $level = 0; + $j = 0; + for ($i=0, $results_count = count($results); $i < $results_count && $j < $match_count; $i++) { + if ($results[$i] == $match[0][$j]) { + // nocache tag + if ($match[1][$j]) { // closing tag + $level--; + unset($results[$i]); + } else { // opening tag + if ($level++ > 0) unset($results[$i]); + } + $j++; + } elseif ($level > 0) { + unset($results[$i]); + } + } + $params['results'] = implode('', $results); + } + $smarty->_cache_info['cache_serials'] = $smarty->_cache_serials; + + // prepend the cache header info into cache file + $_cache_info = serialize($smarty->_cache_info); + $params['results'] = strlen($_cache_info) . "\n" . $_cache_info . $params['results']; + + if (!empty($smarty->cache_handler_func)) { + // use cache_handler function + call_user_func_array($smarty->cache_handler_func, + array('write', &$smarty, &$params['results'], $params['tpl_file'], $params['cache_id'], $params['compile_id'], null)); + } else { + // use local cache file + + if(!@is_writable($smarty->cache_dir)) { + // cache_dir not writable, see if it exists + if(!@is_dir($smarty->cache_dir)) { + $smarty->trigger_error('the $cache_dir \'' . $smarty->cache_dir . '\' does not exist, or is not a directory.', E_USER_ERROR); + return false; + } + $smarty->trigger_error('unable to write to $cache_dir \'' . realpath($smarty->cache_dir) . '\'. Be sure $cache_dir is writable by the web server user.', E_USER_ERROR); + return false; + } + + $_auto_id = $smarty->_get_auto_id($params['cache_id'], $params['compile_id']); + $_cache_file = $smarty->_get_auto_filename($smarty->cache_dir, $params['tpl_file'], $_auto_id); + $_params = array('filename' => $_cache_file, 'contents' => $params['results'], 'create_dirs' => true); + require_once(SMARTY_CORE_DIR . 'core.write_file.php'); + smarty_core_write_file($_params, $smarty); + return true; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.write_compiled_include.php b/BSF/include/smarty/libs/internals/core.write_compiled_include.php new file mode 100644 index 000000000..c14adb5f4 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.write_compiled_include.php @@ -0,0 +1,91 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Extract non-cacheable parts out of compiled template and write it + * + * @param string $compile_path + * @param string $template_compiled + * @return boolean + */ + +function smarty_core_write_compiled_include($params, &$smarty) +{ + $_tag_start = 'if \(\$this->caching && \!\$this->_cache_including\)\: echo \'\{nocache\:('.$params['cache_serial'].')#(\d+)\}\'; endif;'; + $_tag_end = 'if \(\$this->caching && \!\$this->_cache_including\)\: echo \'\{/nocache\:(\\2)#(\\3)\}\'; endif;'; + + preg_match_all('!('.$_tag_start.'(.*)'.$_tag_end.')!Us', + $params['compiled_content'], $_match_source, PREG_SET_ORDER); + + // no nocache-parts found: done + if (count($_match_source)==0) return; + + // convert the matched php-code to functions + $_include_compiled = "<?php /* Smarty version ".$smarty->_version.", created on ".strftime("%Y-%m-%d %H:%M:%S")."\n"; + $_include_compiled .= " compiled from " . strtr(urlencode($params['resource_name']), array('%2F'=>'/', '%3A'=>':')) . " */\n\n"; + + $_compile_path = $params['include_file_path']; + + $smarty->_cache_serials[$_compile_path] = $params['cache_serial']; + $_include_compiled .= "\$this->_cache_serials['".$_compile_path."'] = '".$params['cache_serial']."';\n\n?>"; + + $_include_compiled .= $params['plugins_code']; + $_include_compiled .= "<?php"; + + $this_varname = ((double)phpversion() >= 5.0) ? '_smarty' : 'this'; + for ($_i = 0, $_for_max = count($_match_source); $_i < $_for_max; $_i++) { + $_match =& $_match_source[$_i]; + $source = $_match[4]; + if ($this_varname == '_smarty') { + /* rename $this to $_smarty in the sourcecode */ + $tokens = token_get_all('<?php ' . $_match[4]); + + /* remove trailing <?php */ + $open_tag = ''; + while ($tokens) { + $token = array_shift($tokens); + if (is_array($token)) { + $open_tag .= $token[1]; + } else { + $open_tag .= $token; + } + if ($open_tag == '<?php ') break; + } + + for ($i=0, $count = count($tokens); $i < $count; $i++) { + if (is_array($tokens[$i])) { + if ($tokens[$i][0] == T_VARIABLE && $tokens[$i][1] == '$this') { + $tokens[$i] = '$' . $this_varname; + } else { + $tokens[$i] = $tokens[$i][1]; + } + } + } + $source = implode('', $tokens); + } + + /* add function to compiled include */ + $_include_compiled .= " +function _smarty_tplfunc_$_match[2]_$_match[3](&\$$this_varname) +{ +$source +} + +"; + } + $_include_compiled .= "\n\n?>\n"; + + $_params = array('filename' => $_compile_path, + 'contents' => $_include_compiled, 'create_dirs' => true); + + require_once(SMARTY_CORE_DIR . 'core.write_file.php'); + smarty_core_write_file($_params, $smarty); + return true; +} + + +?> diff --git a/BSF/include/smarty/libs/internals/core.write_compiled_resource.php b/BSF/include/smarty/libs/internals/core.write_compiled_resource.php new file mode 100644 index 000000000..b902eff3c --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.write_compiled_resource.php @@ -0,0 +1,35 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * write the compiled resource + * + * @param string $compile_path + * @param string $compiled_content + * @return true + */ +function smarty_core_write_compiled_resource($params, &$smarty) +{ + if(!@is_writable($smarty->compile_dir)) { + // compile_dir not writable, see if it exists + if(!@is_dir($smarty->compile_dir)) { + $smarty->trigger_error('the $compile_dir \'' . $smarty->compile_dir . '\' does not exist, or is not a directory.', E_USER_ERROR); + return false; + } + $smarty->trigger_error('unable to write to $compile_dir \'' . realpath($smarty->compile_dir) . '\'. Be sure $compile_dir is writable by the web server user.', E_USER_ERROR); + return false; + } + + $_params = array('filename' => $params['compile_path'], 'contents' => $params['compiled_content'], 'create_dirs' => true); + require_once(SMARTY_CORE_DIR . 'core.write_file.php'); + smarty_core_write_file($_params, $smarty); + return true; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/internals/core.write_file.php b/BSF/include/smarty/libs/internals/core.write_file.php new file mode 100644 index 000000000..8a3a3b398 --- /dev/null +++ b/BSF/include/smarty/libs/internals/core.write_file.php @@ -0,0 +1,54 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * write out a file to disk + * + * @param string $filename + * @param string $contents + * @param boolean $create_dirs + * @return boolean + */ +function smarty_core_write_file($params, &$smarty) +{ + $_dirname = dirname($params['filename']); + + if ($params['create_dirs']) { + $_params = array('dir' => $_dirname); + require_once(SMARTY_CORE_DIR . 'core.create_dir_structure.php'); + smarty_core_create_dir_structure($_params, $smarty); + } + + // write to tmp file, then rename it to avoid file locking race condition + $_tmp_file = tempnam($_dirname, 'wrt'); + + if (!($fd = @fopen($_tmp_file, 'wb'))) { + $_tmp_file = $_dirname . DIRECTORY_SEPARATOR . uniqid('wrt'); + if (!($fd = @fopen($_tmp_file, 'wb'))) { + $smarty->trigger_error("problem writing temporary file '$_tmp_file'"); + return false; + } + } + + fwrite($fd, $params['contents']); + fclose($fd); + + if (DIRECTORY_SEPARATOR == '\\' || !@rename($_tmp_file, $params['filename'])) { + // On platforms and filesystems that cannot overwrite with rename() + // delete the file before renaming it -- because windows always suffers + // this, it is short-circuited to avoid the initial rename() attempt + @unlink($params['filename']); + @rename($_tmp_file, $params['filename']); + } + @chmod($params['filename'], $smarty->_file_perms); + + return true; +} + +/* vim: set expandtab: */ + +?>
\ No newline at end of file diff --git a/BSF/include/smarty/libs/plugins/block.textformat.php b/BSF/include/smarty/libs/plugins/block.textformat.php new file mode 100644 index 000000000..8cd010acb --- /dev/null +++ b/BSF/include/smarty/libs/plugins/block.textformat.php @@ -0,0 +1,103 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Smarty {textformat}{/textformat} block plugin + * + * Type: block function<br> + * Name: textformat<br> + * Purpose: format text a certain way with preset styles + * or custom wrap/indent settings<br> + * @link http://smarty.php.net/manual/en/language.function.textformat.php {textformat} + * (Smarty online manual) + * @param array + * <pre> + * Params: style: string (email) + * indent: integer (0) + * wrap: integer (80) + * wrap_char string ("\n") + * indent_char: string (" ") + * wrap_boundary: boolean (true) + * </pre> + * @author Monte Ohrt <monte at ohrt dot com> + * @param string contents of the block + * @param Smarty clever simulation of a method + * @return string string $content re-formatted + */ +function smarty_block_textformat($params, $content, &$smarty) +{ + if (is_null($content)) { + return; + } + + $style = null; + $indent = 0; + $indent_first = 0; + $indent_char = ' '; + $wrap = 80; + $wrap_char = "\n"; + $wrap_cut = false; + $assign = null; + + foreach ($params as $_key => $_val) { + switch ($_key) { + case 'style': + case 'indent_char': + case 'wrap_char': + case 'assign': + $$_key = (string)$_val; + break; + + case 'indent': + case 'indent_first': + case 'wrap': + $$_key = (int)$_val; + break; + + case 'wrap_cut': + $$_key = (bool)$_val; + break; + + default: + $smarty->trigger_error("textformat: unknown attribute '$_key'"); + } + } + + if ($style == 'email') { + $wrap = 72; + } + + // split into paragraphs + $_paragraphs = preg_split('![\r\n][\r\n]!',$content); + $_output = ''; + + for($_x = 0, $_y = count($_paragraphs); $_x < $_y; $_x++) { + if ($_paragraphs[$_x] == '') { + continue; + } + // convert mult. spaces & special chars to single space + $_paragraphs[$_x] = preg_replace(array('!\s+!','!(^\s+)|(\s+$)!'), array(' ',''), $_paragraphs[$_x]); + // indent first line + if($indent_first > 0) { + $_paragraphs[$_x] = str_repeat($indent_char, $indent_first) . $_paragraphs[$_x]; + } + // wordwrap sentences + $_paragraphs[$_x] = wordwrap($_paragraphs[$_x], $wrap - $indent, $wrap_char, $wrap_cut); + // indent lines + if($indent > 0) { + $_paragraphs[$_x] = preg_replace('!^!m', str_repeat($indent_char, $indent), $_paragraphs[$_x]); + } + } + $_output = implode($wrap_char . $wrap_char, $_paragraphs); + + return $assign ? $smarty->assign($assign, $_output) : $_output; + +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/compiler.assign.php b/BSF/include/smarty/libs/plugins/compiler.assign.php new file mode 100644 index 000000000..abef377f8 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/compiler.assign.php @@ -0,0 +1,40 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Smarty {assign} compiler function plugin + * + * Type: compiler function<br> + * Name: assign<br> + * Purpose: assign a value to a template variable + * @link http://smarty.php.net/manual/en/language.custom.functions.php#LANGUAGE.FUNCTION.ASSIGN {assign} + * (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> (initial author) + * @author messju mohr <messju at lammfellpuschen dot de> (conversion to compiler function) + * @param string containing var-attribute and value-attribute + * @param Smarty_Compiler + */ +function smarty_compiler_assign($tag_attrs, &$compiler) +{ + $_params = $compiler->_parse_attrs($tag_attrs); + + if (!isset($_params['var'])) { + $compiler->_syntax_error("assign: missing 'var' parameter", E_USER_WARNING); + return; + } + + if (!isset($_params['value'])) { + $compiler->_syntax_error("assign: missing 'value' parameter", E_USER_WARNING); + return; + } + + return "\$this->assign({$_params['var']}, {$_params['value']});"; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.assign_debug_info.php b/BSF/include/smarty/libs/plugins/function.assign_debug_info.php new file mode 100644 index 000000000..654049876 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.assign_debug_info.php @@ -0,0 +1,40 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Smarty {assign_debug_info} function plugin + * + * Type: function<br> + * Name: assign_debug_info<br> + * Purpose: assign debug info to the template<br> + * @author Monte Ohrt <monte at ohrt dot com> + * @param array unused in this plugin, this plugin uses {@link Smarty::$_config}, + * {@link Smarty::$_tpl_vars} and {@link Smarty::$_smarty_debug_info} + * @param Smarty + */ +function smarty_function_assign_debug_info($params, &$smarty) +{ + $assigned_vars = $smarty->_tpl_vars; + ksort($assigned_vars); + if (@is_array($smarty->_config[0])) { + $config_vars = $smarty->_config[0]; + ksort($config_vars); + $smarty->assign("_debug_config_keys", array_keys($config_vars)); + $smarty->assign("_debug_config_vals", array_values($config_vars)); + } + + $included_templates = $smarty->_smarty_debug_info; + + $smarty->assign("_debug_keys", array_keys($assigned_vars)); + $smarty->assign("_debug_vals", array_values($assigned_vars)); + + $smarty->assign("_debug_tpls", $included_templates); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.config_load.php b/BSF/include/smarty/libs/plugins/function.config_load.php new file mode 100644 index 000000000..db89f638c --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.config_load.php @@ -0,0 +1,142 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Smarty {config_load} function plugin + * + * Type: function<br> + * Name: config_load<br> + * Purpose: load config file vars + * @link http://smarty.php.net/manual/en/language.function.config.load.php {config_load} + * (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @author messju mohr <messju at lammfellpuschen dot de> (added use of resources) + * @param array Format: + * <pre> + * array('file' => required config file name, + * 'section' => optional config file section to load + * 'scope' => local/parent/global + * 'global' => overrides scope, setting to parent if true) + * </pre> + * @param Smarty + */ +function smarty_function_config_load($params, &$smarty) +{ + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $_debug_start_time = smarty_core_get_microtime($_params, $smarty); + } + + $_file = isset($params['file']) ? $smarty->_dequote($params['file']) : null; + $_section = isset($params['section']) ? $smarty->_dequote($params['section']) : null; + $_scope = isset($params['scope']) ? $smarty->_dequote($params['scope']) : 'global'; + $_global = isset($params['global']) ? $smarty->_dequote($params['global']) : false; + + if (!isset($_file) || strlen($_file) == 0) { + $smarty->trigger_error("missing 'file' attribute in config_load tag", E_USER_ERROR, __FILE__, __LINE__); + } + + if (isset($_scope)) { + if ($_scope != 'local' && + $_scope != 'parent' && + $_scope != 'global') { + $smarty->trigger_error("invalid 'scope' attribute value", E_USER_ERROR, __FILE__, __LINE__); + } + } else { + if ($_global) { + $_scope = 'parent'; + } else { + $_scope = 'local'; + } + } + + $_params = array('resource_name' => $_file, + 'resource_base_path' => $smarty->config_dir, + 'get_source' => false); + $smarty->_parse_resource_name($_params); + $_file_path = $_params['resource_type'] . ':' . $_params['resource_name']; + if (isset($_section)) + $_compile_file = $smarty->_get_compile_path($_file_path.'|'.$_section); + else + $_compile_file = $smarty->_get_compile_path($_file_path); + + if($smarty->force_compile || !file_exists($_compile_file)) { + $_compile = true; + } elseif ($smarty->compile_check) { + $_params = array('resource_name' => $_file, + 'resource_base_path' => $smarty->config_dir, + 'get_source' => false); + $_compile = $smarty->_fetch_resource_info($_params) && + $_params['resource_timestamp'] > filemtime($_compile_file); + } else { + $_compile = false; + } + + if($_compile) { + // compile config file + if(!is_object($smarty->_conf_obj)) { + require_once SMARTY_DIR . $smarty->config_class . '.class.php'; + $smarty->_conf_obj = new $smarty->config_class(); + $smarty->_conf_obj->overwrite = $smarty->config_overwrite; + $smarty->_conf_obj->booleanize = $smarty->config_booleanize; + $smarty->_conf_obj->read_hidden = $smarty->config_read_hidden; + $smarty->_conf_obj->fix_newlines = $smarty->config_fix_newlines; + } + + $_params = array('resource_name' => $_file, + 'resource_base_path' => $smarty->config_dir, + $_params['get_source'] = true); + if (!$smarty->_fetch_resource_info($_params)) { + return; + } + $smarty->_conf_obj->set_file_contents($_file, $_params['source_content']); + $_config_vars = array_merge($smarty->_conf_obj->get($_file), + $smarty->_conf_obj->get($_file, $_section)); + if(function_exists('var_export')) { + $_output = '<?php $_config_vars = ' . var_export($_config_vars, true) . '; ?>'; + } else { + $_output = '<?php $_config_vars = unserialize(\'' . strtr(serialize($_config_vars),array('\''=>'\\\'', '\\'=>'\\\\')) . '\'); ?>'; + } + $_params = (array('compile_path' => $_compile_file, 'compiled_content' => $_output, 'resource_timestamp' => $_params['resource_timestamp'])); + require_once(SMARTY_CORE_DIR . 'core.write_compiled_resource.php'); + smarty_core_write_compiled_resource($_params, $smarty); + } else { + include($_compile_file); + } + + if ($smarty->caching) { + $smarty->_cache_info['config'][$_file] = true; + } + + $smarty->_config[0]['vars'] = @array_merge($smarty->_config[0]['vars'], $_config_vars); + $smarty->_config[0]['files'][$_file] = true; + + if ($_scope == 'parent') { + $smarty->_config[1]['vars'] = @array_merge($smarty->_config[1]['vars'], $_config_vars); + $smarty->_config[1]['files'][$_file] = true; + } else if ($_scope == 'global') { + for ($i = 1, $for_max = count($smarty->_config); $i < $for_max; $i++) { + $smarty->_config[$i]['vars'] = @array_merge($smarty->_config[$i]['vars'], $_config_vars); + $smarty->_config[$i]['files'][$_file] = true; + } + } + + if ($smarty->debugging) { + $_params = array(); + require_once(SMARTY_CORE_DIR . 'core.get_microtime.php'); + $smarty->_smarty_debug_info[] = array('type' => 'config', + 'filename' => $_file.' ['.$_section.'] '.$_scope, + 'depth' => $smarty->_inclusion_depth, + 'exec_time' => smarty_core_get_microtime($_params, $smarty) - $_debug_start_time); + } + +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.counter.php b/BSF/include/smarty/libs/plugins/function.counter.php new file mode 100644 index 000000000..1f26db5fb --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.counter.php @@ -0,0 +1,80 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {counter} function plugin + * + * Type: function<br> + * Name: counter<br> + * Purpose: print out a counter value + * @author Monte Ohrt <monte at ohrt dot com> + * @link http://smarty.php.net/manual/en/language.function.counter.php {counter} + * (Smarty online manual) + * @param array parameters + * @param Smarty + * @return string|null + */ +function smarty_function_counter($params, &$smarty) +{ + static $counters = array(); + + $name = (isset($params['name'])) ? $params['name'] : 'default'; + if (!isset($counters[$name])) { + $counters[$name] = array( + 'start'=>1, + 'skip'=>1, + 'direction'=>'up', + 'count'=>1 + ); + } + $counter =& $counters[$name]; + + if (isset($params['start'])) { + $counter['start'] = $counter['count'] = (int)$params['start']; + } + + if (!empty($params['assign'])) { + $counter['assign'] = $params['assign']; + } + + if (isset($counter['assign'])) { + $smarty->assign($counter['assign'], $counter['count']); + } + + if (isset($params['print'])) { + $print = (bool)$params['print']; + } else { + $print = empty($counter['assign']); + } + + if ($print) { + $retval = $counter['count']; + } else { + $retval = null; + } + + if (isset($params['skip'])) { + $counter['skip'] = $params['skip']; + } + + if (isset($params['direction'])) { + $counter['direction'] = $params['direction']; + } + + if ($counter['direction'] == "down") + $counter['count'] -= $counter['skip']; + else + $counter['count'] += $counter['skip']; + + return $retval; + +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.cycle.php b/BSF/include/smarty/libs/plugins/function.cycle.php new file mode 100644 index 000000000..fe78bb87d --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.cycle.php @@ -0,0 +1,102 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Smarty {cycle} function plugin + * + * Type: function<br> + * Name: cycle<br> + * Date: May 3, 2002<br> + * Purpose: cycle through given values<br> + * Input: + * - name = name of cycle (optional) + * - values = comma separated list of values to cycle, + * or an array of values to cycle + * (this can be left out for subsequent calls) + * - reset = boolean - resets given var to true + * - print = boolean - print var or not. default is true + * - advance = boolean - whether or not to advance the cycle + * - delimiter = the value delimiter, default is "," + * - assign = boolean, assigns to template var instead of + * printed. + * + * Examples:<br> + * <pre> + * {cycle values="#eeeeee,#d0d0d0d"} + * {cycle name=row values="one,two,three" reset=true} + * {cycle name=row} + * </pre> + * @link http://smarty.php.net/manual/en/language.function.cycle.php {cycle} + * (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @author credit to Mark Priatel <mpriatel@rogers.com> + * @author credit to Gerard <gerard@interfold.com> + * @author credit to Jason Sweat <jsweat_php@yahoo.com> + * @version 1.3 + * @param array + * @param Smarty + * @return string|null + */ +function smarty_function_cycle($params, &$smarty) +{ + static $cycle_vars; + + $name = (empty($params['name'])) ? 'default' : $params['name']; + $print = (isset($params['print'])) ? (bool)$params['print'] : true; + $advance = (isset($params['advance'])) ? (bool)$params['advance'] : true; + $reset = (isset($params['reset'])) ? (bool)$params['reset'] : false; + + if (!in_array('values', array_keys($params))) { + if(!isset($cycle_vars[$name]['values'])) { + $smarty->trigger_error("cycle: missing 'values' parameter"); + return; + } + } else { + if(isset($cycle_vars[$name]['values']) + && $cycle_vars[$name]['values'] != $params['values'] ) { + $cycle_vars[$name]['index'] = 0; + } + $cycle_vars[$name]['values'] = $params['values']; + } + + $cycle_vars[$name]['delimiter'] = (isset($params['delimiter'])) ? $params['delimiter'] : ','; + + if(is_array($cycle_vars[$name]['values'])) { + $cycle_array = $cycle_vars[$name]['values']; + } else { + $cycle_array = explode($cycle_vars[$name]['delimiter'],$cycle_vars[$name]['values']); + } + + if(!isset($cycle_vars[$name]['index']) || $reset ) { + $cycle_vars[$name]['index'] = 0; + } + + if (isset($params['assign'])) { + $print = false; + $smarty->assign($params['assign'], $cycle_array[$cycle_vars[$name]['index']]); + } + + if($print) { + $retval = $cycle_array[$cycle_vars[$name]['index']]; + } else { + $retval = null; + } + + if($advance) { + if ( $cycle_vars[$name]['index'] >= count($cycle_array) -1 ) { + $cycle_vars[$name]['index'] = 0; + } else { + $cycle_vars[$name]['index']++; + } + } + + return $retval; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.debug.php b/BSF/include/smarty/libs/plugins/function.debug.php new file mode 100644 index 000000000..43452307b --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.debug.php @@ -0,0 +1,35 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {debug} function plugin + * + * Type: function<br> + * Name: debug<br> + * Date: July 1, 2002<br> + * Purpose: popup debug window + * @link http://smarty.php.net/manual/en/language.function.debug.php {debug} + * (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @version 1.0 + * @param array + * @param Smarty + * @return string output from {@link Smarty::_generate_debug_output()} + */ +function smarty_function_debug($params, &$smarty) +{ + if (isset($params['output'])) { + $smarty->assign('_smarty_debug_output', $params['output']); + } + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + return smarty_core_display_debug_console(null, $smarty); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.eval.php b/BSF/include/smarty/libs/plugins/function.eval.php new file mode 100644 index 000000000..ff0472de2 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.eval.php @@ -0,0 +1,49 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {eval} function plugin + * + * Type: function<br> + * Name: eval<br> + * Purpose: evaluate a template variable as a template<br> + * @link http://smarty.php.net/manual/en/language.function.eval.php {eval} + * (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param array + * @param Smarty + */ +function smarty_function_eval($params, &$smarty) +{ + + if (!isset($params['var'])) { + $smarty->trigger_error("eval: missing 'var' parameter"); + return; + } + + if($params['var'] == '') { + return; + } + + $smarty->_compile_source('evaluated template', $params['var'], $_var_compiled); + + ob_start(); + $smarty->_eval('?>' . $_var_compiled); + $_contents = ob_get_contents(); + ob_end_clean(); + + if (!empty($params['assign'])) { + $smarty->assign($params['assign'], $_contents); + } else { + return $_contents; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.fetch.php b/BSF/include/smarty/libs/plugins/function.fetch.php new file mode 100644 index 000000000..81b1bfc6b --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.fetch.php @@ -0,0 +1,221 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {fetch} plugin + * + * Type: function<br> + * Name: fetch<br> + * Purpose: fetch file, web or ftp data and display results + * @link http://smarty.php.net/manual/en/language.function.fetch.php {fetch} + * (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param array + * @param Smarty + * @return string|null if the assign parameter is passed, Smarty assigns the + * result to a template variable + */ +function smarty_function_fetch($params, &$smarty) +{ + if (empty($params['file'])) { + $smarty->_trigger_fatal_error("[plugin] parameter 'file' cannot be empty"); + return; + } + + $content = ''; + if ($smarty->security && !preg_match('!^(http|ftp)://!i', $params['file'])) { + $_params = array('resource_type' => 'file', 'resource_name' => $params['file']); + require_once(SMARTY_CORE_DIR . 'core.is_secure.php'); + if(!smarty_core_is_secure($_params, $smarty)) { + $smarty->_trigger_fatal_error('[plugin] (secure mode) fetch \'' . $params['file'] . '\' is not allowed'); + return; + } + + // fetch the file + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] . '\''); + return; + } + } else { + // not a local file + if(preg_match('!^http://!i',$params['file'])) { + // http fetch + if($uri_parts = parse_url($params['file'])) { + // set defaults + $host = $server_name = $uri_parts['host']; + $timeout = 30; + $accept = "image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*"; + $agent = "Smarty Template Engine ".$smarty->_version; + $referer = ""; + $uri = !empty($uri_parts['path']) ? $uri_parts['path'] : '/'; + $uri .= !empty($uri_parts['query']) ? '?' . $uri_parts['query'] : ''; + $_is_proxy = false; + if(empty($uri_parts['port'])) { + $port = 80; + } else { + $port = $uri_parts['port']; + } + if(!empty($uri_parts['user'])) { + $user = $uri_parts['user']; + } + if(!empty($uri_parts['pass'])) { + $pass = $uri_parts['pass']; + } + // loop through parameters, setup headers + foreach($params as $param_key => $param_value) { + switch($param_key) { + case "file": + case "assign": + case "assign_headers": + break; + case "user": + if(!empty($param_value)) { + $user = $param_value; + } + break; + case "pass": + if(!empty($param_value)) { + $pass = $param_value; + } + break; + case "accept": + if(!empty($param_value)) { + $accept = $param_value; + } + break; + case "header": + if(!empty($param_value)) { + if(!preg_match('![\w\d-]+: .+!',$param_value)) { + $smarty->_trigger_fatal_error("[plugin] invalid header format '".$param_value."'"); + return; + } else { + $extra_headers[] = $param_value; + } + } + break; + case "proxy_host": + if(!empty($param_value)) { + $proxy_host = $param_value; + } + break; + case "proxy_port": + if(!preg_match('!\D!', $param_value)) { + $proxy_port = (int) $param_value; + } else { + $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); + return; + } + break; + case "agent": + if(!empty($param_value)) { + $agent = $param_value; + } + break; + case "referer": + if(!empty($param_value)) { + $referer = $param_value; + } + break; + case "timeout": + if(!preg_match('!\D!', $param_value)) { + $timeout = (int) $param_value; + } else { + $smarty->_trigger_fatal_error("[plugin] invalid value for attribute '".$param_key."'"); + return; + } + break; + default: + $smarty->_trigger_fatal_error("[plugin] unrecognized attribute '".$param_key."'"); + return; + } + } + if(!empty($proxy_host) && !empty($proxy_port)) { + $_is_proxy = true; + $fp = fsockopen($proxy_host,$proxy_port,$errno,$errstr,$timeout); + } else { + $fp = fsockopen($server_name,$port,$errno,$errstr,$timeout); + } + + if(!$fp) { + $smarty->_trigger_fatal_error("[plugin] unable to fetch: $errstr ($errno)"); + return; + } else { + if($_is_proxy) { + fputs($fp, 'GET ' . $params['file'] . " HTTP/1.0\r\n"); + } else { + fputs($fp, "GET $uri HTTP/1.0\r\n"); + } + if(!empty($host)) { + fputs($fp, "Host: $host\r\n"); + } + if(!empty($accept)) { + fputs($fp, "Accept: $accept\r\n"); + } + if(!empty($agent)) { + fputs($fp, "User-Agent: $agent\r\n"); + } + if(!empty($referer)) { + fputs($fp, "Referer: $referer\r\n"); + } + if(isset($extra_headers) && is_array($extra_headers)) { + foreach($extra_headers as $curr_header) { + fputs($fp, $curr_header."\r\n"); + } + } + if(!empty($user) && !empty($pass)) { + fputs($fp, "Authorization: BASIC ".base64_encode("$user:$pass")."\r\n"); + } + + fputs($fp, "\r\n"); + while(!feof($fp)) { + $content .= fgets($fp,4096); + } + fclose($fp); + $csplit = split("\r\n\r\n",$content,2); + + $content = $csplit[1]; + + if(!empty($params['assign_headers'])) { + $smarty->assign($params['assign_headers'],split("\r\n",$csplit[0])); + } + } + } else { + $smarty->_trigger_fatal_error("[plugin] unable to parse URL, check syntax"); + return; + } + } else { + // ftp fetch + if($fp = @fopen($params['file'],'r')) { + while(!feof($fp)) { + $content .= fgets ($fp,4096); + } + fclose($fp); + } else { + $smarty->_trigger_fatal_error('[plugin] fetch cannot read file \'' . $params['file'] .'\''); + return; + } + } + + } + + + if (!empty($params['assign'])) { + $smarty->assign($params['assign'],$content); + } else { + return $content; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.html_checkboxes.php b/BSF/include/smarty/libs/plugins/function.html_checkboxes.php new file mode 100644 index 000000000..ed8ad7f33 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.html_checkboxes.php @@ -0,0 +1,143 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {html_checkboxes} function plugin + * + * File: function.html_checkboxes.php<br> + * Type: function<br> + * Name: html_checkboxes<br> + * Date: 24.Feb.2003<br> + * Purpose: Prints out a list of checkbox input types<br> + * Input:<br> + * - name (optional) - string default "checkbox" + * - values (required) - array + * - options (optional) - associative array + * - checked (optional) - array default not set + * - separator (optional) - ie <br> or + * - output (optional) - the output next to each checkbox + * - assign (optional) - assign the output as an array to this variable + * Examples: + * <pre> + * {html_checkboxes values=$ids output=$names} + * {html_checkboxes values=$ids name='box' separator='<br>' output=$names} + * {html_checkboxes values=$ids checked=$checked separator='<br>' output=$names} + * </pre> + * @link http://smarty.php.net/manual/en/language.function.html.checkboxes.php {html_checkboxes} + * (Smarty online manual) + * @author Christopher Kvarme <christopher.kvarme@flashjab.com> + * @author credits to Monte Ohrt <monte at ohrt dot com> + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_checkboxes($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $name = 'checkbox'; + $values = null; + $options = null; + $selected = null; + $separator = ''; + $labels = true; + $output = null; + + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + case 'separator': + $$_key = $_val; + break; + + case 'labels': + $$_key = (bool)$_val; + break; + + case 'options': + $$_key = (array)$_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array)$_val); + break; + + case 'checked': + case 'selected': + $selected = array_map('strval', array_values((array)$_val)); + break; + + case 'checkboxes': + $smarty->trigger_error('html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead', E_USER_WARNING); + $options = (array)$_val; + break; + + case 'assign': + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_checkboxes: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + settype($selected, 'array'); + $_html_result = array(); + + if (isset($options)) { + + foreach ($options as $_key=>$_val) + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + + + } else { + foreach ($values as $_i=>$_key) { + $_val = isset($output[$_i]) ? $output[$_i] : ''; + $_html_result[] = smarty_function_html_checkboxes_output($name, $_key, $_val, $selected, $extra, $separator, $labels); + } + + } + + if(!empty($params['assign'])) { + $smarty->assign($params['assign'], $_html_result); + } else { + return implode("\n",$_html_result); + } + +} + +function smarty_function_html_checkboxes_output($name, $value, $output, $selected, $extra, $separator, $labels) { + $_output = ''; + if ($labels) $_output .= '<label>'; + $_output .= '<input type="checkbox" name="' + . smarty_function_escape_special_chars($name) . '[]" value="' + . smarty_function_escape_special_chars($value) . '"'; + + if (in_array((string)$value, $selected)) { + $_output .= ' checked="checked"'; + } + $_output .= $extra . ' />' . $output; + if ($labels) $_output .= '</label>'; + $_output .= $separator; + + return $_output; +} + +?> diff --git a/BSF/include/smarty/libs/plugins/function.html_image.php b/BSF/include/smarty/libs/plugins/function.html_image.php new file mode 100644 index 000000000..9abae72ef --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.html_image.php @@ -0,0 +1,142 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {html_image} function plugin + * + * Type: function<br> + * Name: html_image<br> + * Date: Feb 24, 2003<br> + * Purpose: format HTML tags for the image<br> + * Input:<br> + * - file = file (and path) of image (required) + * - height = image height (optional, default actual height) + * - width = image width (optional, default actual width) + * - basedir = base directory for absolute paths, default + * is environment variable DOCUMENT_ROOT + * - path_prefix = prefix for path output (optional, default empty) + * + * Examples: {html_image file="/images/masthead.gif"} + * Output: <img src="/images/masthead.gif" width=400 height=23> + * @link http://smarty.php.net/manual/en/language.function.html.image.php {html_image} + * (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @author credits to Duda <duda@big.hu> - wrote first image function + * in repository, helped with lots of functionality + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_image($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $alt = ''; + $file = ''; + $height = ''; + $width = ''; + $extra = ''; + $prefix = ''; + $suffix = ''; + $path_prefix = ''; + $server_vars = ($smarty->request_use_auto_globals) ? $_SERVER : $GLOBALS['HTTP_SERVER_VARS']; + $basedir = isset($server_vars['DOCUMENT_ROOT']) ? $server_vars['DOCUMENT_ROOT'] : ''; + foreach($params as $_key => $_val) { + switch($_key) { + case 'file': + case 'height': + case 'width': + case 'dpi': + case 'path_prefix': + case 'basedir': + $$_key = $_val; + break; + + case 'alt': + if(!is_array($_val)) { + $$_key = smarty_function_escape_special_chars($_val); + } else { + $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + + case 'link': + case 'href': + $prefix = '<a href="' . $_val . '">'; + $suffix = '</a>'; + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_image: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (empty($file)) { + $smarty->trigger_error("html_image: missing 'file' parameter", E_USER_NOTICE); + return; + } + + if (substr($file,0,1) == '/') { + $_image_path = $basedir . $file; + } else { + $_image_path = $file; + } + + if(!isset($params['width']) || !isset($params['height'])) { + if(!$_image_data = @getimagesize($_image_path)) { + if(!file_exists($_image_path)) { + $smarty->trigger_error("html_image: unable to find '$_image_path'", E_USER_NOTICE); + return; + } else if(!is_readable($_image_path)) { + $smarty->trigger_error("html_image: unable to read '$_image_path'", E_USER_NOTICE); + return; + } else { + $smarty->trigger_error("html_image: '$_image_path' is not a valid image file", E_USER_NOTICE); + return; + } + } + if ($smarty->security && + ($_params = array('resource_type' => 'file', 'resource_name' => $_image_path)) && + (require_once(SMARTY_CORE_DIR . 'core.is_secure.php')) && + (!smarty_core_is_secure($_params, $smarty)) ) { + $smarty->trigger_error("html_image: (secure) '$_image_path' not in secure directory", E_USER_NOTICE); + } + + if(!isset($params['width'])) { + $width = $_image_data[0]; + } + if(!isset($params['height'])) { + $height = $_image_data[1]; + } + + } + + if(isset($params['dpi'])) { + if(strstr($server_vars['HTTP_USER_AGENT'], 'Mac')) { + $dpi_default = 72; + } else { + $dpi_default = 96; + } + $_resize = $dpi_default/$params['dpi']; + $width = round($width * $_resize); + $height = round($height * $_resize); + } + + return $prefix . '<img src="'.$path_prefix.$file.'" alt="'.$alt.'" width="'.$width.'" height="'.$height.'"'.$extra.' />' . $suffix; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.html_options.php b/BSF/include/smarty/libs/plugins/function.html_options.php new file mode 100644 index 000000000..cebadde47 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.html_options.php @@ -0,0 +1,122 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {html_options} function plugin + * + * Type: function<br> + * Name: html_options<br> + * Input:<br> + * - name (optional) - string default "select" + * - values (required if no options supplied) - array + * - options (required if no values supplied) - associative array + * - selected (optional) - string default not set + * - output (required if not options supplied) - array + * Purpose: Prints the list of <option> tags generated from + * the passed parameters + * @link http://smarty.php.net/manual/en/language.function.html.options.php {html_image} + * (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_options($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $name = null; + $values = null; + $options = null; + $selected = array(); + $output = null; + + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + $$_key = (string)$_val; + break; + + case 'options': + $$_key = (array)$_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array)$_val); + break; + + case 'selected': + $$_key = array_map('strval', array_values((array)$_val)); + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_options: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + $_html_result = ''; + + if (isset($options)) { + + foreach ($options as $_key=>$_val) + $_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected); + + } else { + + foreach ($values as $_i=>$_key) { + $_val = isset($output[$_i]) ? $output[$_i] : ''; + $_html_result .= smarty_function_html_options_optoutput($_key, $_val, $selected); + } + + } + + if(!empty($name)) { + $_html_result = '<select name="' . $name . '"' . $extra . '>' . "\n" . $_html_result . '</select>' . "\n"; + } + + return $_html_result; + +} + +function smarty_function_html_options_optoutput($key, $value, $selected) { + if(!is_array($value)) { + $_html_result = '<option label="' . smarty_function_escape_special_chars($value) . '" value="' . + smarty_function_escape_special_chars($key) . '"'; + if (in_array((string)$key, $selected)) + $_html_result .= ' selected="selected"'; + $_html_result .= '>' . smarty_function_escape_special_chars($value) . '</option>' . "\n"; + } else { + $_html_result = smarty_function_html_options_optgroup($key, $value, $selected); + } + return $_html_result; +} + +function smarty_function_html_options_optgroup($key, $values, $selected) { + $optgroup_html = '<optgroup label="' . smarty_function_escape_special_chars($key) . '">' . "\n"; + foreach ($values as $key => $value) { + $optgroup_html .= smarty_function_html_options_optoutput($key, $value, $selected); + } + $optgroup_html .= "</optgroup>\n"; + return $optgroup_html; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.html_radios.php b/BSF/include/smarty/libs/plugins/function.html_radios.php new file mode 100644 index 000000000..7503cfaca --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.html_radios.php @@ -0,0 +1,156 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {html_radios} function plugin + * + * File: function.html_radios.php<br> + * Type: function<br> + * Name: html_radios<br> + * Date: 24.Feb.2003<br> + * Purpose: Prints out a list of radio input types<br> + * Input:<br> + * - name (optional) - string default "radio" + * - values (required) - array + * - options (optional) - associative array + * - checked (optional) - array default not set + * - separator (optional) - ie <br> or + * - output (optional) - the output next to each radio button + * - assign (optional) - assign the output as an array to this variable + * Examples: + * <pre> + * {html_radios values=$ids output=$names} + * {html_radios values=$ids name='box' separator='<br>' output=$names} + * {html_radios values=$ids checked=$checked separator='<br>' output=$names} + * </pre> + * @link http://smarty.php.net/manual/en/language.function.html.radios.php {html_radios} + * (Smarty online manual) + * @author Christopher Kvarme <christopher.kvarme@flashjab.com> + * @author credits to Monte Ohrt <monte at ohrt dot com> + * @version 1.0 + * @param array + * @param Smarty + * @return string + * @uses smarty_function_escape_special_chars() + */ +function smarty_function_html_radios($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + + $name = 'radio'; + $values = null; + $options = null; + $selected = null; + $separator = ''; + $labels = true; + $label_ids = false; + $output = null; + $extra = ''; + + foreach($params as $_key => $_val) { + switch($_key) { + case 'name': + case 'separator': + $$_key = (string)$_val; + break; + + case 'checked': + case 'selected': + if(is_array($_val)) { + $smarty->trigger_error('html_radios: the "' . $_key . '" attribute cannot be an array', E_USER_WARNING); + } else { + $selected = (string)$_val; + } + break; + + case 'labels': + case 'label_ids': + $$_key = (bool)$_val; + break; + + case 'options': + $$_key = (array)$_val; + break; + + case 'values': + case 'output': + $$_key = array_values((array)$_val); + break; + + case 'radios': + $smarty->trigger_error('html_radios: the use of the "radios" attribute is deprecated, use "options" instead', E_USER_WARNING); + $options = (array)$_val; + break; + + case 'assign': + break; + + default: + if(!is_array($_val)) { + $extra .= ' '.$_key.'="'.smarty_function_escape_special_chars($_val).'"'; + } else { + $smarty->trigger_error("html_radios: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (!isset($options) && !isset($values)) + return ''; /* raise error here? */ + + $_html_result = array(); + + if (isset($options)) { + + foreach ($options as $_key=>$_val) + $_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids); + + } else { + + foreach ($values as $_i=>$_key) { + $_val = isset($output[$_i]) ? $output[$_i] : ''; + $_html_result[] = smarty_function_html_radios_output($name, $_key, $_val, $selected, $extra, $separator, $labels, $label_ids); + } + + } + + if(!empty($params['assign'])) { + $smarty->assign($params['assign'], $_html_result); + } else { + return implode("\n",$_html_result); + } + +} + +function smarty_function_html_radios_output($name, $value, $output, $selected, $extra, $separator, $labels, $label_ids) { + $_output = ''; + if ($labels) { + if($label_ids) { + $_id = smarty_function_escape_special_chars(preg_replace('![^\w\-\.]!', '_', $name . '_' . $value)); + $_output .= '<label for="' . $_id . '">'; + } else { + $_output .= '<label>'; + } + } + $_output .= '<input type="radio" name="' + . smarty_function_escape_special_chars($name) . '" value="' + . smarty_function_escape_special_chars($value) . '"'; + + if ($labels && $label_ids) $_output .= ' id="' . $_id . '"'; + + if ((string)$value==$selected) { + $_output .= ' checked="checked"'; + } + $_output .= $extra . ' />' . $output; + if ($labels) $_output .= '</label>'; + $_output .= $separator; + + return $_output; +} + +?> diff --git a/BSF/include/smarty/libs/plugins/function.html_select_date.php b/BSF/include/smarty/libs/plugins/function.html_select_date.php new file mode 100644 index 000000000..e5eb18307 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.html_select_date.php @@ -0,0 +1,331 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Smarty {html_select_date} plugin + * + * Type: function<br> + * Name: html_select_date<br> + * Purpose: Prints the dropdowns for date selection. + * + * ChangeLog:<br> + * - 1.0 initial release + * - 1.1 added support for +/- N syntax for begin + * and end year values. (Monte) + * - 1.2 added support for yyyy-mm-dd syntax for + * time value. (Jan Rosier) + * - 1.3 added support for choosing format for + * month values (Gary Loescher) + * - 1.3.1 added support for choosing format for + * day values (Marcus Bointon) + * - 1.3.2 support negative timestamps, force year + * dropdown to include given date unless explicitly set (Monte) + * - 1.3.4 fix behaviour of 0000-00-00 00:00:00 dates to match that + * of 0000-00-00 dates (cybot, boots) + * @link http://smarty.php.net/manual/en/language.function.html.select.date.php {html_select_date} + * (Smarty online manual) + * @version 1.3.4 + * @author Andrei Zmievski + * @author Monte Ohrt <monte at ohrt dot com> + * @param array + * @param Smarty + * @return string + */ +function smarty_function_html_select_date($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','escape_special_chars'); + require_once $smarty->_get_plugin_filepath('shared','make_timestamp'); + require_once $smarty->_get_plugin_filepath('function','html_options'); + /* Default values. */ + $prefix = "Date_"; + $start_year = strftime("%Y"); + $end_year = $start_year; + $display_days = true; + $display_months = true; + $display_years = true; + $month_format = "%B"; + /* Write months as numbers by default GL */ + $month_value_format = "%m"; + $day_format = "%02d"; + /* Write day values using this format MB */ + $day_value_format = "%d"; + $year_as_text = false; + /* Display years in reverse order? Ie. 2000,1999,.... */ + $reverse_years = false; + /* Should the select boxes be part of an array when returned from PHP? + e.g. setting it to "birthday", would create "birthday[Day]", + "birthday[Month]" & "birthday[Year]". Can be combined with prefix */ + $field_array = null; + /* <select size>'s of the different <select> tags. + If not set, uses default dropdown. */ + $day_size = null; + $month_size = null; + $year_size = null; + /* Unparsed attributes common to *ALL* the <select>/<input> tags. + An example might be in the template: all_extra ='class ="foo"'. */ + $all_extra = null; + /* Separate attributes for the tags. */ + $day_extra = null; + $month_extra = null; + $year_extra = null; + /* Order in which to display the fields. + "D" -> day, "M" -> month, "Y" -> year. */ + $field_order = 'MDY'; + /* String printed between the different fields. */ + $field_separator = "\n"; + $time = time(); + $all_empty = null; + $day_empty = null; + $month_empty = null; + $year_empty = null; + $extra_attrs = ''; + + foreach ($params as $_key=>$_value) { + switch ($_key) { + case 'prefix': + case 'time': + case 'start_year': + case 'end_year': + case 'month_format': + case 'day_format': + case 'day_value_format': + case 'field_array': + case 'day_size': + case 'month_size': + case 'year_size': + case 'all_extra': + case 'day_extra': + case 'month_extra': + case 'year_extra': + case 'field_order': + case 'field_separator': + case 'month_value_format': + case 'month_empty': + case 'day_empty': + case 'year_empty': + $$_key = (string)$_value; + break; + + case 'all_empty': + $$_key = (string)$_value; + $day_empty = $month_empty = $year_empty = $all_empty; + break; + + case 'display_days': + case 'display_months': + case 'display_years': + case 'year_as_text': + case 'reverse_years': + $$_key = (bool)$_value; + break; + + default: + if(!is_array($_value)) { + $extra_attrs .= ' '.$_key.'="'.smarty_function_escape_special_chars($_value).'"'; + } else { + $smarty->trigger_error("html_select_date: extra attribute '$_key' cannot be an array", E_USER_NOTICE); + } + break; + } + } + + if (preg_match('!^-\d+$!', $time)) { + // negative timestamp, use date() + $time = date('Y-m-d', $time); + } + // If $time is not in format yyyy-mm-dd + if (preg_match('/^(\d{0,4}-\d{0,2}-\d{0,2})/', $time, $found)) { + $time = $found[1]; + } else { + // use smarty_make_timestamp to get an unix timestamp and + // strftime to make yyyy-mm-dd + $time = strftime('%Y-%m-%d', smarty_make_timestamp($time)); + } + // Now split this in pieces, which later can be used to set the select + $time = explode("-", $time); + + // make syntax "+N" or "-N" work with start_year and end_year + if (preg_match('!^(\+|\-)\s*(\d+)$!', $end_year, $match)) { + if ($match[1] == '+') { + $end_year = strftime('%Y') + $match[2]; + } else { + $end_year = strftime('%Y') - $match[2]; + } + } + if (preg_match('!^(\+|\-)\s*(\d+)$!', $start_year, $match)) { + if ($match[1] == '+') { + $start_year = strftime('%Y') + $match[2]; + } else { + $start_year = strftime('%Y') - $match[2]; + } + } + if (strlen($time[0]) > 0) { + if ($start_year > $time[0] && !isset($params['start_year'])) { + // force start year to include given date if not explicitly set + $start_year = $time[0]; + } + if($end_year < $time[0] && !isset($params['end_year'])) { + // force end year to include given date if not explicitly set + $end_year = $time[0]; + } + } + + $field_order = strtoupper($field_order); + + $html_result = $month_result = $day_result = $year_result = ""; + + $field_separator_count = -1; + if ($display_months) { + $field_separator_count++; + $month_names = array(); + $month_values = array(); + if(isset($month_empty)) { + $month_names[''] = $month_empty; + $month_values[''] = ''; + } + for ($i = 1; $i <= 12; $i++) { + $month_names[$i] = strftime($month_format, mktime(0, 0, 0, $i, 1, 2000)); + $month_values[$i] = strftime($month_value_format, mktime(0, 0, 0, $i, 1, 2000)); + } + + $month_result .= '<select name='; + if (null !== $field_array){ + $month_result .= '"' . $field_array . '[' . $prefix . 'Month]"'; + } else { + $month_result .= '"' . $prefix . 'Month"'; + } + if (null !== $month_size){ + $month_result .= ' size="' . $month_size . '"'; + } + if (null !== $month_extra){ + $month_result .= ' ' . $month_extra; + } + if (null !== $all_extra){ + $month_result .= ' ' . $all_extra; + } + $month_result .= $extra_attrs . '>'."\n"; + + $month_result .= smarty_function_html_options(array('output' => $month_names, + 'values' => $month_values, + 'selected' => (int)$time[1] ? strftime($month_value_format, mktime(0, 0, 0, (int)$time[1], 1, 2000)) : '', + 'print_result' => false), + $smarty); + $month_result .= '</select>'; + } + + if ($display_days) { + $field_separator_count++; + $days = array(); + if (isset($day_empty)) { + $days[''] = $day_empty; + $day_values[''] = ''; + } + for ($i = 1; $i <= 31; $i++) { + $days[] = sprintf($day_format, $i); + $day_values[] = sprintf($day_value_format, $i); + } + + $day_result .= '<select name='; + if (null !== $field_array){ + $day_result .= '"' . $field_array . '[' . $prefix . 'Day]"'; + } else { + $day_result .= '"' . $prefix . 'Day"'; + } + if (null !== $day_size){ + $day_result .= ' size="' . $day_size . '"'; + } + if (null !== $all_extra){ + $day_result .= ' ' . $all_extra; + } + if (null !== $day_extra){ + $day_result .= ' ' . $day_extra; + } + $day_result .= $extra_attrs . '>'."\n"; + $day_result .= smarty_function_html_options(array('output' => $days, + 'values' => $day_values, + 'selected' => $time[2], + 'print_result' => false), + $smarty); + $day_result .= '</select>'; + } + + if ($display_years) { + $field_separator_count++; + if (null !== $field_array){ + $year_name = $field_array . '[' . $prefix . 'Year]'; + } else { + $year_name = $prefix . 'Year'; + } + if ($year_as_text) { + $year_result .= '<input type="text" name="' . $year_name . '" value="' . $time[0] . '" size="4" maxlength="4"'; + if (null !== $all_extra){ + $year_result .= ' ' . $all_extra; + } + if (null !== $year_extra){ + $year_result .= ' ' . $year_extra; + } + $year_result .= ' />'; + } else { + $years = range((int)$start_year, (int)$end_year); + if ($reverse_years) { + rsort($years, SORT_NUMERIC); + } else { + sort($years, SORT_NUMERIC); + } + $yearvals = $years; + if(isset($year_empty)) { + array_unshift($years, $year_empty); + array_unshift($yearvals, ''); + } + $year_result .= '<select name="' . $year_name . '"'; + if (null !== $year_size){ + $year_result .= ' size="' . $year_size . '"'; + } + if (null !== $all_extra){ + $year_result .= ' ' . $all_extra; + } + if (null !== $year_extra){ + $year_result .= ' ' . $year_extra; + } + $year_result .= $extra_attrs . '>'."\n"; + $year_result .= smarty_function_html_options(array('output' => $years, + 'values' => $yearvals, + 'selected' => $time[0], + 'print_result' => false), + $smarty); + $year_result .= '</select>'; + } + } + + // Loop thru the field_order field + for ($i = 0; $i <= 2; $i++){ + $c = substr($field_order, $i, 1); + switch ($c){ + case 'D': + $html_result .= $day_result; + break; + + case 'M': + $html_result .= $month_result; + break; + + case 'Y': + $html_result .= $year_result; + break; + } + // Add the field seperator + if($i < $field_separator_count) { + $html_result .= $field_separator; + } + } + + return $html_result; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.html_select_time.php b/BSF/include/smarty/libs/plugins/function.html_select_time.php new file mode 100644 index 000000000..2e5be7efe --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.html_select_time.php @@ -0,0 +1,194 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {html_select_time} function plugin + * + * Type: function<br> + * Name: html_select_time<br> + * Purpose: Prints the dropdowns for time selection + * @link http://smarty.php.net/manual/en/language.function.html.select.time.php {html_select_time} + * (Smarty online manual) + * @author Roberto Berto <roberto@berto.net> + * @credits Monte Ohrt <monte AT ohrt DOT com> + * @param array + * @param Smarty + * @return string + * @uses smarty_make_timestamp() + */ +function smarty_function_html_select_time($params, &$smarty) +{ + require_once $smarty->_get_plugin_filepath('shared','make_timestamp'); + require_once $smarty->_get_plugin_filepath('function','html_options'); + /* Default values. */ + $prefix = "Time_"; + $time = time(); + $display_hours = true; + $display_minutes = true; + $display_seconds = true; + $display_meridian = true; + $use_24_hours = true; + $minute_interval = 1; + $second_interval = 1; + /* Should the select boxes be part of an array when returned from PHP? + e.g. setting it to "birthday", would create "birthday[Hour]", + "birthday[Minute]", "birthday[Seconds]" & "birthday[Meridian]". + Can be combined with prefix. */ + $field_array = null; + $all_extra = null; + $hour_extra = null; + $minute_extra = null; + $second_extra = null; + $meridian_extra = null; + + foreach ($params as $_key=>$_value) { + switch ($_key) { + case 'prefix': + case 'time': + case 'field_array': + case 'all_extra': + case 'hour_extra': + case 'minute_extra': + case 'second_extra': + case 'meridian_extra': + $$_key = (string)$_value; + break; + + case 'display_hours': + case 'display_minutes': + case 'display_seconds': + case 'display_meridian': + case 'use_24_hours': + $$_key = (bool)$_value; + break; + + case 'minute_interval': + case 'second_interval': + $$_key = (int)$_value; + break; + + default: + $smarty->trigger_error("[html_select_time] unknown parameter $_key", E_USER_WARNING); + } + } + + $time = smarty_make_timestamp($time); + + $html_result = ''; + + if ($display_hours) { + $hours = $use_24_hours ? range(0, 23) : range(1, 12); + $hour_fmt = $use_24_hours ? '%H' : '%I'; + for ($i = 0, $for_max = count($hours); $i < $for_max; $i++) + $hours[$i] = sprintf('%02d', $hours[$i]); + $html_result .= '<select name='; + if (null !== $field_array) { + $html_result .= '"' . $field_array . '[' . $prefix . 'Hour]"'; + } else { + $html_result .= '"' . $prefix . 'Hour"'; + } + if (null !== $hour_extra){ + $html_result .= ' ' . $hour_extra; + } + if (null !== $all_extra){ + $html_result .= ' ' . $all_extra; + } + $html_result .= '>'."\n"; + $html_result .= smarty_function_html_options(array('output' => $hours, + 'values' => $hours, + 'selected' => strftime($hour_fmt, $time), + 'print_result' => false), + $smarty); + $html_result .= "</select>\n"; + } + + if ($display_minutes) { + $all_minutes = range(0, 59); + for ($i = 0, $for_max = count($all_minutes); $i < $for_max; $i+= $minute_interval) + $minutes[] = sprintf('%02d', $all_minutes[$i]); + $selected = intval(floor(strftime('%M', $time) / $minute_interval) * $minute_interval); + $html_result .= '<select name='; + if (null !== $field_array) { + $html_result .= '"' . $field_array . '[' . $prefix . 'Minute]"'; + } else { + $html_result .= '"' . $prefix . 'Minute"'; + } + if (null !== $minute_extra){ + $html_result .= ' ' . $minute_extra; + } + if (null !== $all_extra){ + $html_result .= ' ' . $all_extra; + } + $html_result .= '>'."\n"; + + $html_result .= smarty_function_html_options(array('output' => $minutes, + 'values' => $minutes, + 'selected' => $selected, + 'print_result' => false), + $smarty); + $html_result .= "</select>\n"; + } + + if ($display_seconds) { + $all_seconds = range(0, 59); + for ($i = 0, $for_max = count($all_seconds); $i < $for_max; $i+= $second_interval) + $seconds[] = sprintf('%02d', $all_seconds[$i]); + $selected = intval(floor(strftime('%S', $time) / $second_interval) * $second_interval); + $html_result .= '<select name='; + if (null !== $field_array) { + $html_result .= '"' . $field_array . '[' . $prefix . 'Second]"'; + } else { + $html_result .= '"' . $prefix . 'Second"'; + } + + if (null !== $second_extra){ + $html_result .= ' ' . $second_extra; + } + if (null !== $all_extra){ + $html_result .= ' ' . $all_extra; + } + $html_result .= '>'."\n"; + + $html_result .= smarty_function_html_options(array('output' => $seconds, + 'values' => $seconds, + 'selected' => $selected, + 'print_result' => false), + $smarty); + $html_result .= "</select>\n"; + } + + if ($display_meridian && !$use_24_hours) { + $html_result .= '<select name='; + if (null !== $field_array) { + $html_result .= '"' . $field_array . '[' . $prefix . 'Meridian]"'; + } else { + $html_result .= '"' . $prefix . 'Meridian"'; + } + + if (null !== $meridian_extra){ + $html_result .= ' ' . $meridian_extra; + } + if (null !== $all_extra){ + $html_result .= ' ' . $all_extra; + } + $html_result .= '>'."\n"; + + $html_result .= smarty_function_html_options(array('output' => array('AM', 'PM'), + 'values' => array('am', 'pm'), + 'selected' => strtolower(strftime('%p', $time)), + 'print_result' => false), + $smarty); + $html_result .= "</select>\n"; + } + + return $html_result; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.html_table.php b/BSF/include/smarty/libs/plugins/function.html_table.php new file mode 100644 index 000000000..32aeba83c --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.html_table.php @@ -0,0 +1,177 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {html_table} function plugin + * + * Type: function<br> + * Name: html_table<br> + * Date: Feb 17, 2003<br> + * Purpose: make an html table from an array of data<br> + * Input:<br> + * - loop = array to loop through + * - cols = number of columns, comma separated list of column names + * or array of column names + * - rows = number of rows + * - table_attr = table attributes + * - th_attr = table heading attributes (arrays are cycled) + * - tr_attr = table row attributes (arrays are cycled) + * - td_attr = table cell attributes (arrays are cycled) + * - trailpad = value to pad trailing cells with + * - caption = text for caption element + * - vdir = vertical direction (default: "down", means top-to-bottom) + * - hdir = horizontal direction (default: "right", means left-to-right) + * - inner = inner loop (default "cols": print $loop line by line, + * $loop will be printed column by column otherwise) + * + * + * Examples: + * <pre> + * {table loop=$data} + * {table loop=$data cols=4 tr_attr='"bgcolor=red"'} + * {table loop=$data cols="first,second,third" tr_attr=$colors} + * </pre> + * @author Monte Ohrt <monte at ohrt dot com> + * @author credit to Messju Mohr <messju at lammfellpuschen dot de> + * @author credit to boots <boots dot smarty at yahoo dot com> + * @version 1.1 + * @link http://smarty.php.net/manual/en/language.function.html.table.php {html_table} + * (Smarty online manual) + * @param array + * @param Smarty + * @return string + */ +function smarty_function_html_table($params, &$smarty) +{ + $table_attr = 'border="1"'; + $tr_attr = ''; + $th_attr = ''; + $td_attr = ''; + $cols = $cols_count = 3; + $rows = 3; + $trailpad = ' '; + $vdir = 'down'; + $hdir = 'right'; + $inner = 'cols'; + $caption = ''; + + if (!isset($params['loop'])) { + $smarty->trigger_error("html_table: missing 'loop' parameter"); + return; + } + + foreach ($params as $_key=>$_value) { + switch ($_key) { + case 'loop': + $$_key = (array)$_value; + break; + + case 'cols': + if (is_array($_value) && !empty($_value)) { + $cols = $_value; + $cols_count = count($_value); + } elseif (!is_numeric($_value) && is_string($_value) && !empty($_value)) { + $cols = explode(',', $_value); + $cols_count = count($cols); + } elseif (!empty($_value)) { + $cols_count = (int)$_value; + } else { + $cols_count = $cols; + } + break; + + case 'rows': + $$_key = (int)$_value; + break; + + case 'table_attr': + case 'trailpad': + case 'hdir': + case 'vdir': + case 'inner': + case 'caption': + $$_key = (string)$_value; + break; + + case 'tr_attr': + case 'td_attr': + case 'th_attr': + $$_key = $_value; + break; + } + } + + $loop_count = count($loop); + if (empty($params['rows'])) { + /* no rows specified */ + $rows = ceil($loop_count/$cols_count); + } elseif (empty($params['cols'])) { + if (!empty($params['rows'])) { + /* no cols specified, but rows */ + $cols_count = ceil($loop_count/$rows); + } + } + + $output = "<table $table_attr>\n"; + + if (!empty($caption)) { + $output .= '<caption>' . $caption . "</caption>\n"; + } + + if (is_array($cols)) { + $cols = ($hdir == 'right') ? $cols : array_reverse($cols); + $output .= "<thead><tr>\n"; + + for ($r=0; $r<$cols_count; $r++) { + $output .= '<th' . smarty_function_html_table_cycle('th', $th_attr, $r) . '>'; + $output .= $cols[$r]; + $output .= "</th>\n"; + } + $output .= "</tr></thead>\n"; + } + + $output .= "<tbody>\n"; + for ($r=0; $r<$rows; $r++) { + $output .= "<tr" . smarty_function_html_table_cycle('tr', $tr_attr, $r) . ">\n"; + $rx = ($vdir == 'down') ? $r*$cols_count : ($rows-1-$r)*$cols_count; + + for ($c=0; $c<$cols_count; $c++) { + $x = ($hdir == 'right') ? $rx+$c : $rx+$cols_count-1-$c; + if ($inner!='cols') { + /* shuffle x to loop over rows*/ + $x = floor($x/$cols_count) + ($x%$cols_count)*$rows; + } + + if ($x<$loop_count) { + $output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">" . $loop[$x] . "</td>\n"; + } else { + $output .= "<td" . smarty_function_html_table_cycle('td', $td_attr, $c) . ">$trailpad</td>\n"; + } + } + $output .= "</tr>\n"; + } + $output .= "</tbody>\n"; + $output .= "</table>\n"; + + return $output; +} + +function smarty_function_html_table_cycle($name, $var, $no) { + if(!is_array($var)) { + $ret = $var; + } else { + $ret = $var[$no % count($var)]; + } + + return ($ret) ? ' '.$ret : ''; +} + + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.mailto.php b/BSF/include/smarty/libs/plugins/function.mailto.php new file mode 100644 index 000000000..20e9ed984 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.mailto.php @@ -0,0 +1,165 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {mailto} function plugin + * + * Type: function<br> + * Name: mailto<br> + * Date: May 21, 2002 + * Purpose: automate mailto address link creation, and optionally + * encode them.<br> + * Input:<br> + * - address = e-mail address + * - text = (optional) text to display, default is address + * - encode = (optional) can be one of: + * * none : no encoding (default) + * * javascript : encode with javascript + * * javascript_charcode : encode with javascript charcode + * * hex : encode with hexidecimal (no javascript) + * - cc = (optional) address(es) to carbon copy + * - bcc = (optional) address(es) to blind carbon copy + * - subject = (optional) e-mail subject + * - newsgroups = (optional) newsgroup(s) to post to + * - followupto = (optional) address(es) to follow up to + * - extra = (optional) extra tags for the href link + * + * Examples: + * <pre> + * {mailto address="me@domain.com"} + * {mailto address="me@domain.com" encode="javascript"} + * {mailto address="me@domain.com" encode="hex"} + * {mailto address="me@domain.com" subject="Hello to you!"} + * {mailto address="me@domain.com" cc="you@domain.com,they@domain.com"} + * {mailto address="me@domain.com" extra='class="mailto"'} + * </pre> + * @link http://smarty.php.net/manual/en/language.function.mailto.php {mailto} + * (Smarty online manual) + * @version 1.2 + * @author Monte Ohrt <monte at ohrt dot com> + * @author credits to Jason Sweat (added cc, bcc and subject functionality) + * @param array + * @param Smarty + * @return string + */ +function smarty_function_mailto($params, &$smarty) +{ + $extra = ''; + + if (empty($params['address'])) { + $smarty->trigger_error("mailto: missing 'address' parameter"); + return; + } else { + $address = $params['address']; + } + + $text = $address; + + // netscape and mozilla do not decode %40 (@) in BCC field (bug?) + // so, don't encode it. + $search = array('%40', '%2C'); + $replace = array('@', ','); + $mail_parms = array(); + foreach ($params as $var=>$value) { + switch ($var) { + case 'cc': + case 'bcc': + case 'followupto': + if (!empty($value)) + $mail_parms[] = $var.'='.str_replace($search,$replace,rawurlencode($value)); + break; + + case 'subject': + case 'newsgroups': + $mail_parms[] = $var.'='.rawurlencode($value); + break; + + case 'extra': + case 'text': + $$var = $value; + + default: + } + } + + $mail_parm_vals = ''; + for ($i=0; $i<count($mail_parms); $i++) { + $mail_parm_vals .= (0==$i) ? '?' : '&'; + $mail_parm_vals .= $mail_parms[$i]; + } + $address .= $mail_parm_vals; + + $encode = (empty($params['encode'])) ? 'none' : $params['encode']; + if (!in_array($encode,array('javascript','javascript_charcode','hex','none')) ) { + $smarty->trigger_error("mailto: 'encode' parameter must be none, javascript or hex"); + return; + } + + if ($encode == 'javascript' ) { + $string = 'document.write(\'<a href="mailto:'.$address.'" '.$extra.'>'.$text.'</a>\');'; + + $js_encode = ''; + for ($x=0; $x < strlen($string); $x++) { + $js_encode .= '%' . bin2hex($string[$x]); + } + + return '<script type="text/javascript">eval(unescape(\''.$js_encode.'\'))</script>'; + + } elseif ($encode == 'javascript_charcode' ) { + $string = '<a href="mailto:'.$address.'" '.$extra.'>'.$text.'</a>'; + + for($x = 0, $y = strlen($string); $x < $y; $x++ ) { + $ord[] = ord($string[$x]); + } + + $_ret = "<script type=\"text/javascript\" language=\"javascript\">\n"; + $_ret .= "<!--\n"; + $_ret .= "{document.write(String.fromCharCode("; + $_ret .= implode(',',$ord); + $_ret .= "))"; + $_ret .= "}\n"; + $_ret .= "//-->\n"; + $_ret .= "</script>\n"; + + return $_ret; + + + } elseif ($encode == 'hex') { + + preg_match('!^(.*)(\?.*)$!',$address,$match); + if(!empty($match[2])) { + $smarty->trigger_error("mailto: hex encoding does not work with extra attributes. Try javascript."); + return; + } + $address_encode = ''; + for ($x=0; $x < strlen($address); $x++) { + if(preg_match('!\w!',$address[$x])) { + $address_encode .= '%' . bin2hex($address[$x]); + } else { + $address_encode .= $address[$x]; + } + } + $text_encode = ''; + for ($x=0; $x < strlen($text); $x++) { + $text_encode .= '&#x' . bin2hex($text[$x]).';'; + } + + $mailto = "mailto:"; + return '<a href="'.$mailto.$address_encode.'" '.$extra.'>'.$text_encode.'</a>'; + + } else { + // no encoding + return '<a href="mailto:'.$address.'" '.$extra.'>'.$text.'</a>'; + + } + +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.math.php b/BSF/include/smarty/libs/plugins/function.math.php new file mode 100644 index 000000000..71672fea4 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.math.php @@ -0,0 +1,84 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {math} function plugin + * + * Type: function<br> + * Name: math<br> + * Purpose: handle math computations in template<br> + * @link http://smarty.php.net/manual/en/language.function.math.php {math} + * (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param array + * @param Smarty + * @return string + */ +function smarty_function_math($params, &$smarty) +{ + // be sure equation parameter is present + if (empty($params['equation'])) { + $smarty->trigger_error("math: missing equation parameter"); + return; + } + + $equation = $params['equation']; + + // make sure parenthesis are balanced + if (substr_count($equation,"(") != substr_count($equation,")")) { + $smarty->trigger_error("math: unbalanced parenthesis"); + return; + } + + // match all vars in equation, make sure all are passed + preg_match_all("!(?:0x[a-fA-F0-9]+)|([a-zA-Z][a-zA-Z0-9_]+)!",$equation, $match); + $allowed_funcs = array('int','abs','ceil','cos','exp','floor','log','log10', + 'max','min','pi','pow','rand','round','sin','sqrt','srand','tan'); + + foreach($match[1] as $curr_var) { + if ($curr_var && !in_array($curr_var, array_keys($params)) && !in_array($curr_var, $allowed_funcs)) { + $smarty->trigger_error("math: function call $curr_var not allowed"); + return; + } + } + + foreach($params as $key => $val) { + if ($key != "equation" && $key != "format" && $key != "assign") { + // make sure value is not empty + if (strlen($val)==0) { + $smarty->trigger_error("math: parameter $key is empty"); + return; + } + if (!is_numeric($val)) { + $smarty->trigger_error("math: parameter $key: is not numeric"); + return; + } + $equation = preg_replace("/\b$key\b/", " \$params['$key'] ", $equation); + } + } + + eval("\$smarty_math_result = ".$equation.";"); + + if (empty($params['format'])) { + if (empty($params['assign'])) { + return $smarty_math_result; + } else { + $smarty->assign($params['assign'],$smarty_math_result); + } + } else { + if (empty($params['assign'])){ + printf($params['format'],$smarty_math_result); + } else { + $smarty->assign($params['assign'],sprintf($params['format'],$smarty_math_result)); + } + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.popup.php b/BSF/include/smarty/libs/plugins/function.popup.php new file mode 100644 index 000000000..3a76b785a --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.popup.php @@ -0,0 +1,119 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {popup} function plugin + * + * Type: function<br> + * Name: popup<br> + * Purpose: make text pop up in windows via overlib + * @link http://smarty.php.net/manual/en/language.function.popup.php {popup} + * (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param array + * @param Smarty + * @return string + */ +function smarty_function_popup($params, &$smarty) +{ + $append = ''; + foreach ($params as $_key=>$_value) { + switch ($_key) { + case 'text': + case 'trigger': + case 'function': + case 'inarray': + $$_key = (string)$_value; + if ($_key == 'function' || $_key == 'inarray') + $append .= ',' . strtoupper($_key) . ",'$_value'"; + break; + + case 'caption': + case 'closetext': + case 'status': + $append .= ',' . strtoupper($_key) . ",'" . str_replace("'","\'",$_value) . "'"; + break; + + case 'fgcolor': + case 'bgcolor': + case 'textcolor': + case 'capcolor': + case 'closecolor': + case 'textfont': + case 'captionfont': + case 'closefont': + case 'fgbackground': + case 'bgbackground': + case 'caparray': + case 'capicon': + case 'background': + case 'frame': + $append .= ',' . strtoupper($_key) . ",'$_value'"; + break; + + case 'textsize': + case 'captionsize': + case 'closesize': + case 'width': + case 'height': + case 'border': + case 'offsetx': + case 'offsety': + case 'snapx': + case 'snapy': + case 'fixx': + case 'fixy': + case 'padx': + case 'pady': + case 'timeout': + case 'delay': + $append .= ',' . strtoupper($_key) . ",$_value"; + break; + + case 'sticky': + case 'left': + case 'right': + case 'center': + case 'above': + case 'below': + case 'noclose': + case 'autostatus': + case 'autostatuscap': + case 'fullhtml': + case 'hauto': + case 'vauto': + case 'mouseoff': + case 'followmouse': + case 'closeclick': + if ($_value) $append .= ',' . strtoupper($_key); + break; + + default: + $smarty->trigger_error("[popup] unknown parameter $_key", E_USER_WARNING); + } + } + + if (empty($text) && !isset($inarray) && empty($function)) { + $smarty->trigger_error("overlib: attribute 'text' or 'inarray' or 'function' required"); + return false; + } + + if (empty($trigger)) { $trigger = "onmouseover"; } + + $retval = $trigger . '="return overlib(\''.preg_replace(array("!'!","![\r\n]!"),array("\'",'\r'),$text).'\''; + $retval .= $append . ');"'; + if ($trigger == 'onmouseover') + $retval .= ' onmouseout="nd();"'; + + + return $retval; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/function.popup_init.php b/BSF/include/smarty/libs/plugins/function.popup_init.php new file mode 100644 index 000000000..93cb45450 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/function.popup_init.php @@ -0,0 +1,40 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty {popup_init} function plugin + * + * Type: function<br> + * Name: popup_init<br> + * Purpose: initialize overlib + * @link http://smarty.php.net/manual/en/language.function.popup.init.php {popup_init} + * (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param array + * @param Smarty + * @return string + */ +function smarty_function_popup_init($params, &$smarty) +{ + $zindex = 1000; + + if (!empty($params['zindex'])) { + $zindex = $params['zindex']; + } + + if (!empty($params['src'])) { + return '<div id="overDiv" style="position:absolute; visibility:hidden; z-index:'.$zindex.';"></div>' . "\n" + . '<script type="text/javascript" language="JavaScript" src="'.$params['src'].'"></script>' . "\n"; + } else { + $smarty->trigger_error("popup_init: missing src parameter"); + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.capitalize.php b/BSF/include/smarty/libs/plugins/modifier.capitalize.php new file mode 100644 index 000000000..4a611d9f0 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.capitalize.php @@ -0,0 +1,43 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty capitalize modifier plugin + * + * Type: modifier<br> + * Name: capitalize<br> + * Purpose: capitalize words in the string + * @link http://smarty.php.net/manual/en/language.modifiers.php#LANGUAGE.MODIFIER.CAPITALIZE + * capitalize (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @return string + */ +function smarty_modifier_capitalize($string, $uc_digits = false) +{ + smarty_modifier_capitalize_ucfirst(null, $uc_digits); + return preg_replace_callback('!\'?\b\w(\w|\')*\b!', 'smarty_modifier_capitalize_ucfirst', $string); +} + +function smarty_modifier_capitalize_ucfirst($string, $uc_digits = null) +{ + static $_uc_digits = false; + + if(isset($uc_digits)) { + $_uc_digits = $uc_digits; + return; + } + + if(substr($string[0],0,1) != "'" && !preg_match("!\d!",$string[0]) || $_uc_digits) + return ucfirst($string[0]); + else + return $string[0]; +} + + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.cat.php b/BSF/include/smarty/libs/plugins/modifier.cat.php new file mode 100644 index 000000000..2e37940d4 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.cat.php @@ -0,0 +1,33 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty cat modifier plugin + * + * Type: modifier<br> + * Name: cat<br> + * Date: Feb 24, 2003 + * Purpose: catenate a value to a variable + * Input: string to catenate + * Example: {$var|cat:"foo"} + * @link http://smarty.php.net/manual/en/language.modifier.cat.php cat + * (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @version 1.0 + * @param string + * @param string + * @return string + */ +function smarty_modifier_cat($string, $cat) +{ + return $string . $cat; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.count_characters.php b/BSF/include/smarty/libs/plugins/modifier.count_characters.php new file mode 100644 index 000000000..5ed9a87cd --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.count_characters.php @@ -0,0 +1,32 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty count_characters modifier plugin + * + * Type: modifier<br> + * Name: count_characteres<br> + * Purpose: count the number of characters in a text + * @link http://smarty.php.net/manual/en/language.modifier.count.characters.php + * count_characters (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @param boolean include whitespace in the character count + * @return integer + */ +function smarty_modifier_count_characters($string, $include_spaces = false) +{ + if ($include_spaces) + return(strlen($string)); + + return preg_match_all("/[^\s]/",$string, $match); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.count_paragraphs.php b/BSF/include/smarty/libs/plugins/modifier.count_paragraphs.php new file mode 100644 index 000000000..e0e274da7 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.count_paragraphs.php @@ -0,0 +1,29 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty count_paragraphs modifier plugin + * + * Type: modifier<br> + * Name: count_paragraphs<br> + * Purpose: count the number of paragraphs in a text + * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php + * count_paragraphs (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @return integer + */ +function smarty_modifier_count_paragraphs($string) +{ + // count \r or \n characters + return count(preg_split('/[\r\n]+/', $string)); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.count_sentences.php b/BSF/include/smarty/libs/plugins/modifier.count_sentences.php new file mode 100644 index 000000000..f66ea1703 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.count_sentences.php @@ -0,0 +1,29 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty count_sentences modifier plugin + * + * Type: modifier<br> + * Name: count_sentences + * Purpose: count the number of sentences in a text + * @link http://smarty.php.net/manual/en/language.modifier.count.paragraphs.php + * count_sentences (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @return integer + */ +function smarty_modifier_count_sentences($string) +{ + // find periods with a word before but not after. + return preg_match_all('/[^\s]\.(?!\w)/', $string, $match); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.count_words.php b/BSF/include/smarty/libs/plugins/modifier.count_words.php new file mode 100644 index 000000000..9d339f542 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.count_words.php @@ -0,0 +1,33 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty count_words modifier plugin + * + * Type: modifier<br> + * Name: count_words<br> + * Purpose: count the number of words in a text + * @link http://smarty.php.net/manual/en/language.modifier.count.words.php + * count_words (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @return integer + */ +function smarty_modifier_count_words($string) +{ + // split text by ' ',\r,\n,\f,\t + $split_array = preg_split('/\s+/',$string); + // count matches that contain alphanumerics + $word_count = preg_grep('/[a-zA-Z0-9\\x80-\\xff]/', $split_array); + + return count($word_count); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.date_format.php b/BSF/include/smarty/libs/plugins/modifier.date_format.php new file mode 100644 index 000000000..8cf7d5e14 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.date_format.php @@ -0,0 +1,58 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Include the {@link shared.make_timestamp.php} plugin + */ +require_once $smarty->_get_plugin_filepath('shared', 'make_timestamp'); +/** + * Smarty date_format modifier plugin + * + * Type: modifier<br> + * Name: date_format<br> + * Purpose: format datestamps via strftime<br> + * Input:<br> + * - string: input date string + * - format: strftime format for output + * - default_date: default date if $string is empty + * @link http://smarty.php.net/manual/en/language.modifier.date.format.php + * date_format (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @param string + * @param string + * @return string|void + * @uses smarty_make_timestamp() + */ +function smarty_modifier_date_format($string, $format = '%b %e, %Y', $default_date = '') +{ + if ($string != '') { + $timestamp = smarty_make_timestamp($string); + } elseif ($default_date != '') { + $timestamp = smarty_make_timestamp($default_date); + } else { + return; + } + if (DIRECTORY_SEPARATOR == '\\') { + $_win_from = array('%D', '%h', '%n', '%r', '%R', '%t', '%T'); + $_win_to = array('%m/%d/%y', '%b', "\n", '%I:%M:%S %p', '%H:%M', "\t", '%H:%M:%S'); + if (strpos($format, '%e') !== false) { + $_win_from[] = '%e'; + $_win_to[] = sprintf('%\' 2d', date('j', $timestamp)); + } + if (strpos($format, '%l') !== false) { + $_win_from[] = '%l'; + $_win_to[] = sprintf('%\' 2d', date('h', $timestamp)); + } + $format = str_replace($_win_from, $_win_to, $format); + } + return strftime($format, $timestamp); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.debug_print_var.php b/BSF/include/smarty/libs/plugins/modifier.debug_print_var.php new file mode 100644 index 000000000..e4f7bc0cc --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.debug_print_var.php @@ -0,0 +1,90 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty debug_print_var modifier plugin + * + * Type: modifier<br> + * Name: debug_print_var<br> + * Purpose: formats variable contents for display in the console + * @link http://smarty.php.net/manual/en/language.modifier.debug.print.var.php + * debug_print_var (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param array|object + * @param integer + * @param integer + * @return string + */ +function smarty_modifier_debug_print_var($var, $depth = 0, $length = 40) +{ + $_replace = array( + "\n" => '<i>\n</i>', + "\r" => '<i>\r</i>', + "\t" => '<i>\t</i>' + ); + + switch (gettype($var)) { + case 'array' : + $results = '<b>Array (' . count($var) . ')</b>'; + foreach ($var as $curr_key => $curr_val) { + $results .= '<br>' . str_repeat(' ', $depth * 2) + . '<b>' . strtr($curr_key, $_replace) . '</b> => ' + . smarty_modifier_debug_print_var($curr_val, ++$depth, $length); + $depth--; + } + break; + case 'object' : + $object_vars = get_object_vars($var); + $results = '<b>' . get_class($var) . ' Object (' . count($object_vars) . ')</b>'; + foreach ($object_vars as $curr_key => $curr_val) { + $results .= '<br>' . str_repeat(' ', $depth * 2) + . '<b> ->' . strtr($curr_key, $_replace) . '</b> = ' + . smarty_modifier_debug_print_var($curr_val, ++$depth, $length); + $depth--; + } + break; + case 'boolean' : + case 'NULL' : + case 'resource' : + if (true === $var) { + $results = 'true'; + } elseif (false === $var) { + $results = 'false'; + } elseif (null === $var) { + $results = 'null'; + } else { + $results = htmlspecialchars((string) $var); + } + $results = '<i>' . $results . '</i>'; + break; + case 'integer' : + case 'float' : + $results = htmlspecialchars((string) $var); + break; + case 'string' : + $results = strtr($var, $_replace); + if (strlen($var) > $length ) { + $results = substr($var, 0, $length - 3) . '...'; + } + $results = htmlspecialchars('"' . $results . '"'); + break; + case 'unknown type' : + default : + $results = strtr((string) $var, $_replace); + if (strlen($results) > $length ) { + $results = substr($results, 0, $length - 3) . '...'; + } + $results = htmlspecialchars($results); + } + + return $results; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.default.php b/BSF/include/smarty/libs/plugins/modifier.default.php new file mode 100644 index 000000000..70011fd6b --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.default.php @@ -0,0 +1,32 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty default modifier plugin + * + * Type: modifier<br> + * Name: default<br> + * Purpose: designate default value for empty variables + * @link http://smarty.php.net/manual/en/language.modifier.default.php + * default (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @param string + * @return string + */ +function smarty_modifier_default($string, $default = '') +{ + if (!isset($string) || $string === '') + return $default; + else + return $string; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.escape.php b/BSF/include/smarty/libs/plugins/modifier.escape.php new file mode 100644 index 000000000..a2f52b232 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.escape.php @@ -0,0 +1,93 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty escape modifier plugin + * + * Type: modifier<br> + * Name: escape<br> + * Purpose: Escape the string according to escapement type + * @link http://smarty.php.net/manual/en/language.modifier.escape.php + * escape (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @param html|htmlall|url|quotes|hex|hexentity|javascript + * @return string + */ +function smarty_modifier_escape($string, $esc_type = 'html', $char_set = 'ISO-8859-1') +{ + switch ($esc_type) { + case 'html': + return htmlspecialchars($string, ENT_QUOTES, $char_set); + + case 'htmlall': + return htmlentities($string, ENT_QUOTES, $char_set); + + case 'url': + return rawurlencode($string); + + case 'urlpathinfo': + return str_replace('%2F','/',rawurlencode($string)); + + case 'quotes': + // escape unescaped single quotes + return preg_replace("%(?<!\\\\)'%", "\\'", $string); + + case 'hex': + // escape every character into hex + $return = ''; + for ($x=0; $x < strlen($string); $x++) { + $return .= '%' . bin2hex($string[$x]); + } + return $return; + + case 'hexentity': + $return = ''; + for ($x=0; $x < strlen($string); $x++) { + $return .= '&#x' . bin2hex($string[$x]) . ';'; + } + return $return; + + case 'decentity': + $return = ''; + for ($x=0; $x < strlen($string); $x++) { + $return .= '&#' . ord($string[$x]) . ';'; + } + return $return; + + case 'javascript': + // escape quotes and backslashes, newlines, etc. + return strtr($string, array('\\'=>'\\\\',"'"=>"\\'",'"'=>'\\"',"\r"=>'\\r',"\n"=>'\\n','</'=>'<\/')); + + case 'mail': + // safe way to display e-mail address on a web page + return str_replace(array('@', '.'),array(' [AT] ', ' [DOT] '), $string); + + case 'nonstd': + // escape non-standard chars, such as ms document quotes + $_res = ''; + for($_i = 0, $_len = strlen($string); $_i < $_len; $_i++) { + $_ord = ord(substr($string, $_i, 1)); + // non-standard char, escape it + if($_ord >= 126){ + $_res .= '&#' . $_ord . ';'; + } + else { + $_res .= substr($string, $_i, 1); + } + } + return $_res; + + default: + return $string; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.indent.php b/BSF/include/smarty/libs/plugins/modifier.indent.php new file mode 100644 index 000000000..394147a29 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.indent.php @@ -0,0 +1,28 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty indent modifier plugin + * + * Type: modifier<br> + * Name: indent<br> + * Purpose: indent lines of text + * @link http://smarty.php.net/manual/en/language.modifier.indent.php + * indent (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @param integer + * @param string + * @return string + */ +function smarty_modifier_indent($string,$chars=4,$char=" ") +{ + return preg_replace('!^!m',str_repeat($char,$chars),$string); +} + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.lower.php b/BSF/include/smarty/libs/plugins/modifier.lower.php new file mode 100644 index 000000000..20e7a8d39 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.lower.php @@ -0,0 +1,26 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty lower modifier plugin + * + * Type: modifier<br> + * Name: lower<br> + * Purpose: convert string to lowercase + * @link http://smarty.php.net/manual/en/language.modifier.lower.php + * lower (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @return string + */ +function smarty_modifier_lower($string) +{ + return strtolower($string); +} + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.nl2br.php b/BSF/include/smarty/libs/plugins/modifier.nl2br.php new file mode 100644 index 000000000..d6fabff64 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.nl2br.php @@ -0,0 +1,35 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty plugin + * + * Type: modifier<br> + * Name: nl2br<br> + * Date: Feb 26, 2003 + * Purpose: convert \r\n, \r or \n to <<br>> + * Input:<br> + * - contents = contents to replace + * - preceed_test = if true, includes preceeding break tags + * in replacement + * Example: {$text|nl2br} + * @link http://smarty.php.net/manual/en/language.modifier.nl2br.php + * nl2br (Smarty online manual) + * @version 1.0 + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @return string + */ +function smarty_modifier_nl2br($string) +{ + return nl2br($string); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.regex_replace.php b/BSF/include/smarty/libs/plugins/modifier.regex_replace.php new file mode 100644 index 000000000..d1f1545d8 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.regex_replace.php @@ -0,0 +1,37 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty regex_replace modifier plugin + * + * Type: modifier<br> + * Name: regex_replace<br> + * Purpose: regular expression search/replace + * @link http://smarty.php.net/manual/en/language.modifier.regex.replace.php + * regex_replace (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @param string|array + * @param string|array + * @return string + */ +function smarty_modifier_regex_replace($string, $search, $replace) +{ + if (($pos = strpos($search,"\0")) !== false) + $search = substr($search,0,$pos); + if (preg_match('!([a-zA-Z\s]+)$!s', $search, $match) && (strpos($match[1], 'e') !== false)) { + /* remove eval-modifier from $search */ + $search = substr($search, 0, -strlen($match[1])) . preg_replace('![e\s]+!', '', $match[1]); + } + + return preg_replace($search, $replace, $string); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.replace.php b/BSF/include/smarty/libs/plugins/modifier.replace.php new file mode 100644 index 000000000..df041c884 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.replace.php @@ -0,0 +1,30 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty replace modifier plugin + * + * Type: modifier<br> + * Name: replace<br> + * Purpose: simple search/replace + * @link http://smarty.php.net/manual/en/language.modifier.replace.php + * replace (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @param string + * @param string + * @return string + */ +function smarty_modifier_replace($string, $search, $replace) +{ + return str_replace($search, $replace, $string); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.spacify.php b/BSF/include/smarty/libs/plugins/modifier.spacify.php new file mode 100644 index 000000000..c2423f4f2 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.spacify.php @@ -0,0 +1,30 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty spacify modifier plugin + * + * Type: modifier<br> + * Name: spacify<br> + * Purpose: add spaces between characters in a string + * @link http://smarty.php.net/manual/en/language.modifier.spacify.php + * spacify (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @param string + * @return string + */ +function smarty_modifier_spacify($string, $spacify_char = ' ') +{ + return implode($spacify_char, + preg_split('//', $string, -1, PREG_SPLIT_NO_EMPTY)); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.string_format.php b/BSF/include/smarty/libs/plugins/modifier.string_format.php new file mode 100644 index 000000000..9e051a578 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.string_format.php @@ -0,0 +1,29 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty string_format modifier plugin + * + * Type: modifier<br> + * Name: string_format<br> + * Purpose: format strings via sprintf + * @link http://smarty.php.net/manual/en/language.modifier.string.format.php + * string_format (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @param string + * @return string + */ +function smarty_modifier_string_format($string, $format) +{ + return sprintf($format, $string); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.strip.php b/BSF/include/smarty/libs/plugins/modifier.strip.php new file mode 100644 index 000000000..cc5c453c8 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.strip.php @@ -0,0 +1,33 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty strip modifier plugin + * + * Type: modifier<br> + * Name: strip<br> + * Purpose: Replace all repeated spaces, newlines, tabs + * with a single space or supplied replacement string.<br> + * Example: {$var|strip} {$var|strip:" "} + * Date: September 25th, 2002 + * @link http://smarty.php.net/manual/en/language.modifier.strip.php + * strip (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @version 1.0 + * @param string + * @param string + * @return string + */ +function smarty_modifier_strip($text, $replace = ' ') +{ + return preg_replace('!\s+!', $replace, $text); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.strip_tags.php b/BSF/include/smarty/libs/plugins/modifier.strip_tags.php new file mode 100644 index 000000000..93011a892 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.strip_tags.php @@ -0,0 +1,32 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty strip_tags modifier plugin + * + * Type: modifier<br> + * Name: strip_tags<br> + * Purpose: strip html tags from text + * @link http://smarty.php.net/manual/en/language.modifier.strip.tags.php + * strip_tags (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @param boolean + * @return string + */ +function smarty_modifier_strip_tags($string, $replace_with_space = true) +{ + if ($replace_with_space) + return preg_replace('!<[^>]*?>!', ' ', $string); + else + return strip_tags($string); +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.truncate.php b/BSF/include/smarty/libs/plugins/modifier.truncate.php new file mode 100644 index 000000000..35c89690a --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.truncate.php @@ -0,0 +1,50 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty truncate modifier plugin + * + * Type: modifier<br> + * Name: truncate<br> + * Purpose: Truncate a string to a certain length if necessary, + * optionally splitting in the middle of a word, and + * appending the $etc string or inserting $etc into the middle. + * @link http://smarty.php.net/manual/en/language.modifier.truncate.php + * truncate (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @param integer + * @param string + * @param boolean + * @param boolean + * @return string + */ +function smarty_modifier_truncate($string, $length = 80, $etc = '...', + $break_words = false, $middle = false) +{ + if ($length == 0) + return ''; + + if (strlen($string) > $length) { + $length -= min($length, strlen($etc)); + if (!$break_words && !$middle) { + $string = preg_replace('/\s+?(\S+)?$/', '', substr($string, 0, $length+1)); + } + if(!$middle) { + return substr($string, 0, $length) . $etc; + } else { + return substr($string, 0, $length/2) . $etc . substr($string, -$length/2); + } + } else { + return $string; + } +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.upper.php b/BSF/include/smarty/libs/plugins/modifier.upper.php new file mode 100644 index 000000000..c12480fbd --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.upper.php @@ -0,0 +1,26 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty upper modifier plugin + * + * Type: modifier<br> + * Name: upper<br> + * Purpose: convert string to uppercase + * @link http://smarty.php.net/manual/en/language.modifier.upper.php + * upper (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @return string + */ +function smarty_modifier_upper($string) +{ + return strtoupper($string); +} + +?> diff --git a/BSF/include/smarty/libs/plugins/modifier.wordwrap.php b/BSF/include/smarty/libs/plugins/modifier.wordwrap.php new file mode 100644 index 000000000..ce0718156 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/modifier.wordwrap.php @@ -0,0 +1,29 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Smarty wordwrap modifier plugin + * + * Type: modifier<br> + * Name: wordwrap<br> + * Purpose: wrap a string of text at a given length + * @link http://smarty.php.net/manual/en/language.modifier.wordwrap.php + * wordwrap (Smarty online manual) + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @param integer + * @param string + * @param boolean + * @return string + */ +function smarty_modifier_wordwrap($string,$length=80,$break="\n",$cut=false) +{ + return wordwrap($string,$length,$break,$cut); +} + +?> diff --git a/BSF/include/smarty/libs/plugins/outputfilter.trimwhitespace.php b/BSF/include/smarty/libs/plugins/outputfilter.trimwhitespace.php new file mode 100644 index 000000000..97b0d21e8 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/outputfilter.trimwhitespace.php @@ -0,0 +1,75 @@ +<?php +/** + * Smarty plugin + * @package Smarty + * @subpackage plugins + */ + +/** + * Smarty trimwhitespace outputfilter plugin + * + * File: outputfilter.trimwhitespace.php<br> + * Type: outputfilter<br> + * Name: trimwhitespace<br> + * Date: Jan 25, 2003<br> + * Purpose: trim leading white space and blank lines from + * template source after it gets interpreted, cleaning + * up code and saving bandwidth. Does not affect + * <<PRE>></PRE> and <SCRIPT></SCRIPT> blocks.<br> + * Install: Drop into the plugin directory, call + * <code>$smarty->load_filter('output','trimwhitespace');</code> + * from application. + * @author Monte Ohrt <monte at ohrt dot com> + * @author Contributions from Lars Noschinski <lars@usenet.noschinski.de> + * @version 1.3 + * @param string + * @param Smarty + */ +function smarty_outputfilter_trimwhitespace($source, &$smarty) +{ + // Pull out the script blocks + preg_match_all("!<script[^>]+>.*?</script>!is", $source, $match); + $_script_blocks = $match[0]; + $source = preg_replace("!<script[^>]+>.*?</script>!is", + '@@@SMARTY:TRIM:SCRIPT@@@', $source); + + // Pull out the pre blocks + preg_match_all("!<pre>.*?</pre>!is", $source, $match); + $_pre_blocks = $match[0]; + $source = preg_replace("!<pre>.*?</pre>!is", + '@@@SMARTY:TRIM:PRE@@@', $source); + + // Pull out the textarea blocks + preg_match_all("!<textarea[^>]+>.*?</textarea>!is", $source, $match); + $_textarea_blocks = $match[0]; + $source = preg_replace("!<textarea[^>]+>.*?</textarea>!is", + '@@@SMARTY:TRIM:TEXTAREA@@@', $source); + + // remove all leading spaces, tabs and carriage returns NOT + // preceeded by a php close tag. + $source = trim(preg_replace('/((?<!\?>)\n)[\s]+/m', '\1', $source)); + + // replace textarea blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:TEXTAREA@@@",$_textarea_blocks, $source); + + // replace pre blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:PRE@@@",$_pre_blocks, $source); + + // replace script blocks + smarty_outputfilter_trimwhitespace_replace("@@@SMARTY:TRIM:SCRIPT@@@",$_script_blocks, $source); + + return $source; +} + +function smarty_outputfilter_trimwhitespace_replace($search_str, $replace, &$subject) { + $_len = strlen($search_str); + $_pos = 0; + for ($_i=0, $_count=count($replace); $_i<$_count; $_i++) + if (($_pos=strpos($subject, $search_str, $_pos))!==false) + $subject = substr_replace($subject, $replace[$_i], $_pos, $_len); + else + break; + +} + +?> diff --git a/BSF/include/smarty/libs/plugins/shared.escape_special_chars.php b/BSF/include/smarty/libs/plugins/shared.escape_special_chars.php new file mode 100644 index 000000000..c07ce31be --- /dev/null +++ b/BSF/include/smarty/libs/plugins/shared.escape_special_chars.php @@ -0,0 +1,31 @@ +<?php +/** + * Smarty shared plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * escape_special_chars common function + * + * Function: smarty_function_escape_special_chars<br> + * Purpose: used by other smarty functions to escape + * special chars except for already escaped ones + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @return string + */ +function smarty_function_escape_special_chars($string) +{ + if(!is_array($string)) { + $string = preg_replace('!&(#?\w+);!', '%%%SMARTY_START%%%\\1%%%SMARTY_END%%%', $string); + $string = htmlspecialchars($string); + $string = str_replace(array('%%%SMARTY_START%%%','%%%SMARTY_END%%%'), array('&',';'), $string); + } + return $string; +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/smarty/libs/plugins/shared.make_timestamp.php b/BSF/include/smarty/libs/plugins/shared.make_timestamp.php new file mode 100644 index 000000000..b42eb11d8 --- /dev/null +++ b/BSF/include/smarty/libs/plugins/shared.make_timestamp.php @@ -0,0 +1,46 @@ +<?php +/** + * Smarty shared plugin + * @package Smarty + * @subpackage plugins + */ + + +/** + * Function: smarty_make_timestamp<br> + * Purpose: used by other smarty functions to make a timestamp + * from a string. + * @author Monte Ohrt <monte at ohrt dot com> + * @param string + * @return string + */ +function smarty_make_timestamp($string) +{ + if(empty($string)) { + // use "now": + $time = time(); + + } elseif (preg_match('/^\d{14}$/', $string)) { + // it is mysql timestamp format of YYYYMMDDHHMMSS? + $time = mktime(substr($string, 8, 2),substr($string, 10, 2),substr($string, 12, 2), + substr($string, 4, 2),substr($string, 6, 2),substr($string, 0, 4)); + + } elseif (is_numeric($string)) { + // it is a numeric string, we handle it as timestamp + $time = (int)$string; + + } else { + // strtotime should handle it + $time = strtotime($string); + if ($time == -1 || $time === false) { + // strtotime() was not able to parse $string, use "now": + $time = time(); + } + } + return $time; + +} + +/* vim: set expandtab: */ + +?> diff --git a/BSF/include/template.class.php b/BSF/include/template.class.php new file mode 100644 index 000000000..1fd3c94ac --- /dev/null +++ b/BSF/include/template.class.php @@ -0,0 +1,385 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + + +require_once 'smarty/libs/Smarty.class.php'; + +// migrate lang:XXX +// sed "s/{lang:\([^}]\+\)}/{\'\1\'|@translate}/g" my_template.tpl +// migrate change root level vars {XXX} +// sed "s/{pwg_root}/{ROOT_URL}/g" my_template.tpl +// migrate change root level vars {XXX} +// sed "s/{\([a-zA-Z_]\+\)}/{$\1}/g" my_template.tpl +// migrate all +// cat my_template.tpl | sed "s/{lang:\([^}]\+\)}/{\'\1\'|@translate}/g" | sed "s/{pwg_root}/{ROOT_URL}/g" | sed "s/{\([a-zA-Z_]\+\)}/{$\1}/g" + + +class Template { + + var $smarty; + + var $output = ''; + + // Hash of filenames for each template handle. + var $files = array(); + + // used by html_head smarty block to add content before </head> + var $html_head_elements = array(); + + function Template($root = ".", $theme= "") + { + global $conf; + + $this->smarty = new Smarty; + $this->smarty->debugging = $conf['debug_template']; + + if ( isset($conf['compiled_template_dir'] ) ) + { + $compile_dir = $conf['compiled_template_dir']; + } + else + { + $compile_dir = $conf['local_data_dir']; + if ( !is_dir($compile_dir) ) + { + mkdir( $compile_dir, 0777); + file_put_contents($compile_dir.'/index.htm', ''); + } + $compile_dir .= '/templates_c'; + } + if ( !is_dir($compile_dir) ) + { + mkdir( $compile_dir, 0777 ); + file_put_contents($compile_dir.'/index.htm', ''); + } + + $this->smarty->compile_dir = $compile_dir; + + $this->smarty->assign_by_ref( 'pwg', new PwgTemplateAdapter() ); + $this->smarty->register_modifier( 'translate', array('Template', 'mod_translate') ); + $this->smarty->register_modifier( 'explode', array('Template', 'mod_explode') ); + $this->smarty->register_block('html_head', array(&$this, 'block_html_head') ); + if ( $conf['compiled_template_cache_language'] ) + { + $this->smarty->register_prefilter( array(&$this, 'prefilter_language') ); + } + + if ( !empty($theme) ) + { + include($root.'/theme/'.$theme.'/themeconf.inc.php'); + $this->smarty->assign('themeconf', $themeconf); + } + + $this->set_template_dir($root); + } + + /** + * Sets the template root directory for this Template object. + */ + function set_template_dir($dir) + { + $this->smarty->template_dir = $dir; + + $real_dir = realpath($dir); + $compile_id = crc32( $real_dir===false ? $dir : $real_dir); + $this->smarty->compile_id = base_convert($compile_id, 10, 36 ); + } + + /** + * Gets the template root directory for this Template object. + */ + function get_template_dir() + { + return $this->smarty->template_dir; + } + + /** + * Deletes all compiled templates. + */ + function delete_compiled_templates() + { + $save_compile_id = $this->smarty->compile_id; + $this->smarty->compile_id = null; + $this->smarty->clear_compiled_tpl(); + $this->smarty->compile_id = $save_compile_id; + file_put_contents($this->smarty->compile_dir.'/index.htm', ''); + } + + function get_themeconf($val) + { + $tc = $this->smarty->get_template_vars('themeconf'); + return isset($tc[$val]) ? $tc[$val] : ''; + } + + /** + * Sets the template filename for handle. + */ + function set_filename($handle, $filename) + { + return $this->set_filenames( array($handle=>$filename) ); + } + + /** + * Sets the template filenames for handles. $filename_array should be a + * hash of handle => filename pairs. + */ + function set_filenames($filename_array) + { + if (!is_array($filename_array)) + { + return false; + } + + reset($filename_array); + while(list($handle, $filename) = each($filename_array)) + { + if (is_null($filename)) + unset( $this->files[$handle] ); + else + $this->files[$handle] = $filename; + } + return true; + } + + /** see smarty assign http://www.smarty.net/manual/en/api.assign.php */ + function assign($tpl_var, $value = null) + { + $this->smarty->assign( $tpl_var, $value ); + } + + /** + * Inserts the uncompiled code for $handle as the value of $varname in the + * root-level. This can be used to effectively include a template in the + * middle of another template. + * This is equivalent to assign($varname, $this->parse($handle, true)) + */ + function assign_var_from_handle($varname, $handle) + { + $this->assign($varname, $this->parse($handle, true)); + return true; + } + + /** see smarty append http://www.smarty.net/manual/en/api.append.php */ + function append($tpl_var, $value=null, $merge=false) + { + $this->smarty->append( $tpl_var, $value, $merge ); + } + + /** + * Root-level variable concatenation. Appends a string to an existing + * variable assignment with the same name. + */ + function concat($tpl_var, $value) + { + $old_val = & $this->smarty->get_template_vars($tpl_var); + if ( isset($old_val) ) + { + $old_val .= $value; + } + else + { + $this->assign($tpl_var, $value); + } + } + + /** see smarty append http://www.smarty.net/manual/en/api.clear_assign.php */ + function clear_assign($tpl_var) + { + $this->smarty->clear_assign( $tpl_var ); + } + + /** see smarty get_template_vars http://www.smarty.net/manual/en/api.get_template_vars.php */ + function &get_template_vars($name=null) + { + return $this->smarty->get_template_vars( $name ); + } + + + /** + * Load the file for the handle, eventually compile the file and run the compiled + * code. This will add the output to the results or return the result if $return + * is true. + */ + function parse($handle, $return=false) + { + if ( !isset($this->files[$handle]) ) + { + die("Template->parse(): Couldn't load template file for handle $handle"); + } + + $this->smarty->assign( 'ROOT_URL', get_root_url() ); + $this->smarty->assign( 'TAG_INPUT_ENABLED', + ((is_adviser()) ? 'disabled="disabled" onclick="return false;"' : '')); + + global $conf, $lang_info; + if ( $conf['compiled_template_cache_language'] and isset($lang_info['code']) ) + { + $save_compile_id = $this->smarty->compile_id; + $this->smarty->compile_id .= '.'.$lang_info['code']; + } + + $v = $this->smarty->fetch($this->files[$handle], null, null, false); + + if (isset ($save_compile_id) ) + { + $this->smarty->compile_id = $save_compile_id; + } + + if ($return) + { + return $v; + } + $this->output .= $v; + } + + /** + * Load the file for the handle, eventually compile the file and run the compiled + * code. This will print out the results of executing the template. + */ + function pparse($handle) + { + $this->parse($handle, false); + $this->flush(); + } + + function flush() + { + if ( count($this->html_head_elements) ) + { + $search = "\n</head>"; + $pos = strpos( $this->output, $search ); + if ($pos !== false) + { + $this->output = substr_replace( $this->output, "\n".implode( "\n", $this->html_head_elements ), $pos, 0 ); + } //else maybe error or warning ? + $this->html_head_elements = array(); + } + echo $this->output; + $this->output=''; + } + + /** flushes the output */ + function p() + { + $start = get_moment(); + + $this->flush(); + + if ($this->smarty->debugging) + { + global $t2; + $this->smarty->assign( + array( + 'AAAA_DEBUG_OUTPUT_TIME__' => get_elapsed_time($start, get_moment()), + 'AAAA_DEBUG_TOTAL_TIME__' => get_elapsed_time($t2, get_moment()) + ) + ); + require_once(SMARTY_CORE_DIR . 'core.display_debug_console.php'); + echo smarty_core_display_debug_console(null, $this->smarty); + } + } + + /** + * translate variable modifier - translates a text to the currently loaded + * language + */ + /*static*/ function mod_translate($text) + { + return l10n($text); + } + + /** + * explode variable modifier - similar to php explode + * 'Yes;No'|@explode:';' -> array('Yes', 'No') + */ + /*static*/ function mod_explode($text, $delimiter=',') + { + return explode($delimiter, $text); + } + + /** + * This smarty "html_head" block allows to add content just before + * </head> element in the output after the head has been parsed. This is + * handy in order to respect strict standards when <style> and <link> + * html elements must appear in the <head> element + */ + function block_html_head($params, $content, &$smarty, &$repeat) + { + $content = trim($content); + if ( !empty($content) ) + { // second call + if ( empty($this->output) ) + {//page header not parsed yet + $this->append('head_elements', $content); + } + else + { + $this->html_head_elements[] = $content; + } + } + } + + /** + * Smarty prefilter to allow caching (whenever possible) language strings + * from templates. + */ + function prefilter_language($source, &$smarty) + { + global $lang; + $ldq = preg_quote($this->smarty->left_delimiter, '~'); + $rdq = preg_quote($this->smarty->right_delimiter, '~'); + + $regex = "~$ldq *\'([^'$]+)\'\|@translate *$rdq~"; + $source = preg_replace( $regex.'e', 'isset($lang[\'$1\']) ? $lang[\'$1\'] : \'$0\'', $source); + + $regex = "~$ldq *\'([^'$]+)\'\|@translate\|~"; + $source = preg_replace( $regex.'e', 'isset($lang[\'$1\']) ? \'{\'.var_export($lang[\'$1\'],true).\'|\' : \'$0\'', $source); + + return $source; + } +} + +/** + * This class contains basic functions that can be called directly from the + * templates in the form $pwg->l10n('edit') + */ +class PwgTemplateAdapter +{ + function l10n($text) + { + return l10n($text); + } + + function l10n_dec($s, $p, $v) + { + return l10n_dec($s, $p, $v); + } + + function sprintf() + { + $args = func_get_args(); + return call_user_func_array('sprintf', $args ); + } +} + +?> diff --git a/BSF/include/upload.class.php b/BSF/include/upload.class.php new file mode 100644 index 000000000..f9587ddb8 --- /dev/null +++ b/BSF/include/upload.class.php @@ -0,0 +1,41 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +class Upload +{ + function Upload() + { + } + + /** + * Return list of Uploadable categories + * + * @param void + * @return array + */ + function get_cat() + { + } +} + +?> diff --git a/BSF/include/user.inc.php b/BSF/include/user.inc.php new file mode 100644 index 000000000..b267790f8 --- /dev/null +++ b/BSF/include/user.inc.php @@ -0,0 +1,74 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// by default we start with guest +$user['id'] = $conf['guest_id']; + +if (isset($_COOKIE[session_name()])) +{ + session_start(); + if (isset($_GET['act']) and $_GET['act'] == 'logout') + { // logout + $_SESSION = array(); + session_unset(); + session_destroy(); + setcookie(session_name(),'',0, + ini_get('session.cookie_path'), + ini_get('session.cookie_domain') + ); + setcookie($conf['remember_me_name'], '', 0, cookie_path()); + redirect(make_index_url()); + } + elseif (!empty($_SESSION['pwg_uid'])) + { + $user['id'] = $_SESSION['pwg_uid']; + } +} + +// Now check the auto-login +if ( $user['id']==$conf['guest_id'] ) +{ + auto_login(); +} + +if (session_id()=="") +{ + session_start(); +} + +// using Apache authentication override the above user search +if ($conf['apache_authentication'] and isset($_SERVER['REMOTE_USER'])) +{ + if (!($user['id'] = get_userid($_SERVER['REMOTE_USER']))) + { + register_user($_SERVER['REMOTE_USER'], '', '', false); + $user['id'] = get_userid($_SERVER['REMOTE_USER']); + } +} + +$user = build_user( $user['id'], + ( defined('IN_ADMIN') and IN_ADMIN ) ? false : true // use cache ? + ); + +trigger_action('user_init', $user); +?> diff --git a/BSF/include/ws_core.inc.php b/BSF/include/ws_core.inc.php new file mode 100644 index 000000000..c78d4f402 --- /dev/null +++ b/BSF/include/ws_core.inc.php @@ -0,0 +1,619 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/**** WEB SERVICE CORE CLASSES************************************************ + * PwgServer - main object - the link between web service methods, request + * handler and response encoder + * PwgRequestHandler - base class for handlers + * PwgResponseEncoder - base class for response encoders + * PwgError, PwgNamedArray, PwgNamedStruct - can be used by web service functions + * as return values + */ + + +define( 'WS_PARAM_ACCEPT_ARRAY', 0x010000 ); +define( 'WS_PARAM_FORCE_ARRAY', 0x030000 ); +define( 'WS_PARAM_OPTIONAL', 0x040000 ); + +define( 'WS_ERR_INVALID_METHOD', 1001 ); +define( 'WS_ERR_MISSING_PARAM', 1002 ); +define( 'WS_ERR_INVALID_PARAM', 1003 ); + +define( 'WS_XML_ATTRIBUTES', 'attributes_xml_'); +define( 'WS_XML_CONTENT', 'content_xml_'); + +/** + * PwgError object can be returned from any web service function implementation. + */ +class PwgError +{ + var $_code; + var $_codeText; + + function PwgError($code, $codeText) + { + $this->_code = $code; + $this->_codeText = $codeText; + } + + function code() { return $this->_code; } + function message() { return $this->_codeText; } +} + +/** + * Simple wrapper around an array (keys are consecutive integers starting at 0). + * Provides naming clues for xml output (xml attributes vs. xml child elements?) + * Usually returned by web service function implementation. + */ +class PwgNamedArray +{ + /*private*/ var $_content; + /*private*/ var $_itemName; + /*private*/ var $_xmlAttributes; + + /** + * Constructs a named array + * @param arr array (keys must be consecutive integers starting at 0) + * @param itemName string xml element name for values of arr (e.g. image) + * @param xmlAttributes array of sub-item attributes that will be encoded as + * xml attributes instead of xml child elements + */ + function PwgNamedArray(&$arr, $itemName, $xmlAttributes=array() ) + { + $this->_content = $arr; + $this->_itemName = $itemName; + $this->_xmlAttributes = array_flip($xmlAttributes); + } +} +/** + * Simple wrapper around a "struct" (php array whose keys are not consecutive + * integers starting at 0). Provides naming clues for xml output (what is xml + * attributes and what is element) + */ +class PwgNamedStruct +{ + /*private*/ var $_content; + /*private*/ var $_name; + /*private*/ var $_xmlAttributes; + + /** + * Constructs a named struct (usually returned by web service function + * implementation) + * @param name string - containing xml element name + * @param content array - the actual content (php array) + * @param xmlAttributes array - name of the keys in $content that will be + * encoded as xml attributes (if null - automatically prefer xml attributes + * whenever possible) + */ + function PwgNamedStruct($name, $content, $xmlAttributes=null, $xmlElements=null ) + { + $this->_name = $name; + $this->_content = $content; + if ( isset($xmlAttributes) ) + { + $this->_xmlAttributes = array_flip($xmlAttributes); + } + else + { + $this->_xmlAttributes = array(); + foreach ($this->_content as $key=>$value) + { + if (!empty($key) and (is_scalar($value) or is_null($value)) ) + { + if ( empty($xmlElements) or !in_array($key,$xmlElements) ) + { + $this->_xmlAttributes[$key]=1; + } + } + } + } + } +} + + +/** + * Replace array_walk_recursive() + * + * @category PHP + * @package PHP_Compat + * @link http://php.net/function.array_walk_recursive + * @author Tom Buskens <ortega@php.net> + * @author Aidan Lister <aidan@php.net> + * @version $Revision$ + * @since PHP 5 + * @require PHP 4.0.6 (is_callable) + */ +if (!function_exists('array_walk_recursive')) { + function array_walk_recursive(&$input, $funcname) + { + if (!is_callable($funcname)) { + if (is_array($funcname)) { + $funcname = $funcname[0] . '::' . $funcname[1]; + } + user_error('array_walk_recursive() Not a valid callback ' . $user_func, + E_USER_WARNING); + return; + } + + if (!is_array($input)) { + user_error('array_walk_recursive() The argument should be an array', + E_USER_WARNING); + return; + } + + $args = func_get_args(); + + foreach ($input as $key => $item) { + if (is_array($item)) { + array_walk_recursive($item, $funcname, $args); + $input[$key] = $item; + } else { + $args[0] = &$item; + $args[1] = &$key; + call_user_func_array($funcname, $args); + $input[$key] = $item; + } + } + } +} + +/** + * Abstract base class for request handlers. + */ +class PwgRequestHandler +{ + /** Virtual abstract method. Decodes the request (GET or POST) handles the + * method invocation as well as response sending. + */ + function handleRequest(&$server) { assert(false); } +} + +/** + * + * Base class for web service response encoder. + */ +class PwgResponseEncoder +{ + /** encodes the web service response to the appropriate output format + * @param response mixed the unencoded result of a service method call + */ + function encodeResponse($response) { assert(false); } + + /** default "Content-Type" http header for this kind of response format + */ + function getContentType() { assert(false); } + + /** + * returns true if the parameter is a 'struct' (php array type whose keys are + * NOT consecutive integers starting with 0) + */ + function is_struct(&$data) + { + if (is_array($data) ) + { + if (range(0, count($data) - 1) !== array_keys($data) ) + { # string keys, unordered, non-incremental keys, .. - whatever, make object + return true; + } + } + return false; + } + + /** + * removes all XML formatting from $response (named array, named structs, etc) + * usually called by every response encoder, except rest xml. + */ + function flattenResponse(&$response) + { + PwgResponseEncoder::_mergeAttributesAndContent($response); + PwgResponseEncoder::_removeNamedArray($response); + PwgResponseEncoder::_removeNamedStruct($response); + if (is_array($response)) + { // need to call 2 times (first time might add new arrays) + array_walk_recursive($response, array('PwgResponseEncoder', '_remove_named_callback') ); + array_walk_recursive($response, array('PwgResponseEncoder', '_remove_named_callback') ); + } +//print_r($response); + PwgResponseEncoder::_mergeAttributesAndContent($response); + } + + /*private*/ function _remove_named_callback(&$value, $key) + { + do + { + $changed = 0; + $changed += PwgResponseEncoder::_removeNamedArray($value); + $changed += PwgResponseEncoder::_removeNamedStruct($value); + // print_r('walk '.$key."<br/>\n"); + } + while ($changed); + } + + /*private*/ function _mergeAttributesAndContent(&$value) + { + if ( !is_array($value) ) + return; +/* $first_key = ''; + if (count($value)) { $ak = array_keys($value); $first_key = $ak[0]; } + + print_r( '_mergeAttributesAndContent is_struct='.PwgResponseEncoder::is_struct($value) + .' count='.count($value) + .' first_key='.$first_key + ."<br/>\n" + );*/ + $ret = 0; + if (PwgResponseEncoder::is_struct($value)) + { + if ( isset($value[WS_XML_ATTRIBUTES]) ) + { + $value = array_merge( $value, $value[WS_XML_ATTRIBUTES] ); + unset( $value[WS_XML_ATTRIBUTES] ); + $ret=1; + } + if ( isset($value[WS_XML_CONTENT]) ) + { + $cont_processed = 0; + if ( count($value)==1 ) + { + $value = $value[WS_XML_CONTENT]; + $cont_processed=1; + } + else + { + if (PwgResponseEncoder::is_struct($value[WS_XML_CONTENT])) + { + $value = array_merge( $value, $value[WS_XML_CONTENT] ); + unset( $value[WS_XML_CONTENT] ); + $cont_processed=1; + } + } + $ret += $cont_processed; + if (!$cont_processed) + { + $value['_content'] = $value[WS_XML_CONTENT]; + unset( $value[WS_XML_CONTENT] ); + $ret++; + } + } + } + + foreach ($value as $key=>$v) + { + if ( PwgResponseEncoder::_mergeAttributesAndContent($v) ) + { + $value[$key]=$v; + $ret++; + } + } + return $ret; + } + + /*private*/ function _removeNamedArray(&$value) + { + if ( strtolower( get_class($value) ) =='pwgnamedarray') + { + $value = $value->_content; + return 1; + } + return 0; + } + + /*private*/ function _removeNamedStruct(&$value) + { + if ( strtolower( get_class($value) ) =='pwgnamedstruct') + { + if ( isset($value->_content['']) ) + { + $unknown = $value->_content['']; + unset( $value->_content[''] ); + $value->_content[$value->_name] = $unknown; + } + $value = $value->_content; + return 1; + } + return 0; + } +} + + + +class PwgServer +{ + var $_requestHandler; + var $_requestFormat; + var $_responseEncoder; + var $_responseFormat; + + var $_methods; + var $_methodSignatures; + + function PwgServer() + { + $methods = array(); + } + + /** + * Initializes the request handler. + */ + function setHandler($requestFormat, &$requestHandler) + { + $this->_requestHandler = &$requestHandler; + $this->_requestFormat = $requestFormat; + } + + /** + * Initializes the request handler. + */ + function setEncoder($responseFormat, &$encoder) + { + $this->_responseEncoder = &$encoder; + $this->_responseFormat = $responseFormat; + } + + /** + * Runs the web service call (handler and response encoder should have been + * created) + */ + function run() + { + if ( is_null($this->_responseEncoder) ) + { + set_status_header(500); + @header("Content-Type: text/plain"); + echo ("Cannot process your request. Unknown response format. +Request format: ".@$this->_requestFormat." handler:".$this->_requestHandler." +Response format: ".@$this->_responseFormat." encoder:".$this->_responseEncoder." + "); + var_export($this); + die(0); + } + + if ( is_null($this->_requestHandler) ) + { + $this->sendResponse( + new PwgError(500, 'Unknown request format') + ); + return; + } + + $this->addMethod('reflection.getMethodList', + array('PwgServer', 'ws_getMethodList'), + null, '' ); + $this->addMethod('reflection.getMethodDetails', + array('PwgServer', 'ws_getMethodDetails'), + array('methodName'),''); + + trigger_action('ws_add_methods', array(&$this) ); + uksort( $this->_methods, 'strnatcmp' ); + $this->_requestHandler->handleRequest($this); + } + + /** + * Encodes a response and sends it back to the browser. + */ + function sendResponse($response) + { + $encodedResponse = $this->_responseEncoder->encodeResponse($response); + $contentType = $this->_responseEncoder->getContentType(); + + @header('Content-Type: '.$contentType); + print_r($encodedResponse); + } + + /** + * Registers a web service method. + * @param methodName string - the name of the method as seen externally + * @param callback mixed - php method to be invoked internally + * @param params array - map of allowed parameter names with optional default + * values and parameter flags. Example of $params: + * array( 'param1' => array('default'=>523, 'flags'=>WS_PARAM_FORCE_ARRAY) ) . + * Possible parameter flags are: + * WS_PARAM_ALLOW_ARRAY - this parameter can be an array + * WS_PARAM_FORCE_ARRAY - if this parameter is scalar, force it to an array + * before invoking the method + * @param description string - a description of the method. + */ + function addMethod($methodName, $callback, $params=array(), $description, $include_file='') + { + $this->_methods[$methodName] = $callback; + $this->_methodDescriptions[$methodName] = $description; + + if (!is_array($params)) + { + $params = array(); + } + + if ( range(0, count($params) - 1) === array_keys($params) ) + { + $params = array_flip($params); + } + + foreach( $params as $param=>$options) + { + if ( !is_array($options) ) + { + $params[$param] = array('flags'=>0); + } + else + { + $flags = isset($options['flags']) ? $options['flags'] : 0; + if ( array_key_exists('default', $options) ) + { + $flags |= WS_PARAM_OPTIONAL; + } + if ( $flags & WS_PARAM_FORCE_ARRAY ) + { + $flags |= WS_PARAM_ACCEPT_ARRAY; + } + $options['flags'] = $flags; + $params[$param] = $options; + } + } + $this->_methodSignatures[$methodName] = $params; + } + + function hasMethod($methodName) + { + return isset($this->_methods[$methodName]); + } + + function getMethodDescription($methodName) + { + $desc = @$this->_methodDescriptions[$methodName]; + return isset($desc) ? $desc : ''; + } + + function getMethodSignature($methodName) + { + $signature = @$this->_methodSignatures[$methodName]; + return isset($signature) ? $signature : array(); + } + + /*static*/ function isPost() + { + return isset($HTTP_RAW_POST_DATA) or !empty($_POST); + } + + /*static*/ function makeArrayParam(&$param) + { + if ( $param==null ) + { + $param = array(); + } + else + { + if (! is_array($param) ) + { + $param = array($param); + } + } + } + + /** + * Invokes a registered method. Returns the return of the method (or + * a PwgError object if the method is not found) + * @param methodName string the name of the method to invoke + * @param params array array of parameters to pass to the invoked method + */ + function invoke($methodName, $params) + { + $callback = @$this->_methods[$methodName]; + + if ( $callback==null ) + { + return new PwgError(WS_ERR_INVALID_METHOD, 'Method name "'.$methodName.'" is not valid'); + } + + // parameter check and data coercion ! + $signature = @$this->_methodSignatures[$methodName]; + $missing_params = array(); + foreach($signature as $name=>$options) + { + $flags = $options['flags']; + if ( !array_key_exists($name, $params) ) + {// parameter not provided in the request + if ( !($flags&WS_PARAM_OPTIONAL) ) + { + $missing_params[] = $name; + } + else if ( array_key_exists('default',$options) ) + { + $params[$name] = $options['default']; + if ( ($flags&WS_PARAM_FORCE_ARRAY) ) + { + $this->makeArrayParam( $params[$name] ); + } + } + } + else + {// parameter provided - do some basic checks + $the_param = $params[$name]; + if ( is_array($the_param) and ($flags&WS_PARAM_ACCEPT_ARRAY)==0 ) + { + return new PwgError(WS_ERR_INVALID_PARAM, $name.' must be scalar' ); + } + if ( ($flags&WS_PARAM_FORCE_ARRAY) ) + { + $this->makeArrayParam( $the_param ); + } + if ( isset($options['maxValue']) and $the_param>$options['maxValue']) + { + $the_param = $options['maxValue']; + } + $params[$name] = $the_param; + } + } + if (count($missing_params)) + { + return new PwgError(WS_ERR_MISSING_PARAM, 'Missing parameters: '.implode(',',$missing_params)); + } + $result = trigger_event('ws_invoke_allowed', true, $methodName, $params); + if ( strtolower( get_class($result) )!='pwgerror') + { + $result = call_user_func_array($callback, array($params, &$this) ); + } + return $result; + } + + /** + * WS reflection method implementation: lists all available methods + */ + /*static*/ function ws_getMethodList($params, &$service) + { + return array('methods' => new PwgNamedArray( array_keys($service->_methods),'method' ) ); + } + + /** + * WS reflection method implementation: gets information about a given method + */ + /*static*/ function ws_getMethodDetails($params, &$service) + { + $methodName = $params['methodName']; + if (!$service->hasMethod($methodName)) + { + return new PwgError(WS_ERR_INVALID_PARAM, + 'Requested method does not exist'); + } + $res = array( + 'name' => $methodName, + 'description' => $service->getMethodDescription($methodName), + 'params' => array(), + ); + $signature = $service->getMethodSignature($methodName); + foreach ($signature as $name => $options) + { + $param_data = array( + 'name' => $name, + 'optional' => ($options['flags']&WS_PARAM_OPTIONAL)?true:false, + 'acceptArray' => ($options['flags']&WS_PARAM_ACCEPT_ARRAY)?true:false, + ); + if (isset($options['default'])) + { + $param_data['defaultValue'] = $options['default']; + } + $res['params'][] = $param_data; + } + return $res; + } +} +?> diff --git a/BSF/include/ws_functions.inc.php b/BSF/include/ws_functions.inc.php new file mode 100644 index 000000000..2488fd0bf --- /dev/null +++ b/BSF/include/ws_functions.inc.php @@ -0,0 +1,1103 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +/**** IMPLEMENTATION OF WEB SERVICE METHODS ***********************************/ + +/** + * Event handler for method invocation security check. Should return a PwgError + * if the preconditions are not satifsied for method invocation. + */ +function ws_isInvokeAllowed($res, $methodName, $params) +{ + global $conf, $calling_partner_id; + + if ( strpos($methodName,'reflection.')===0 ) + { // OK for reflection + return $res; + } + + if ( !is_autorize_status(ACCESS_GUEST) and + strpos($methodName,'pwg.session.')!==0 ) + { + return new PwgError(401, 'Access denied'); + } + + if ( !$conf['ws_access_control'] ) + { + return $res; // No controls are requested + } + $query = ' +SELECT * FROM '.WEB_SERVICES_ACCESS_TABLE." + WHERE `name` = '$calling_partner_id' + AND NOW() <= end; "; + $result = pwg_query($query); + $row = mysql_fetch_assoc($result); + if ( empty($row) ) + { + return new PwgError(403, 'Partner id does not exist or is expired'); + } + if ( !empty($row['request']) + and strpos($methodName, $row['request'])==false + and strpos($methodName, 'session')==false + and strpos($methodName, 'getVersion')==false ) + { // session and getVersion are allowed to diagnose any failure reason + return new PwgError(403, 'Method not allowed'); + } + + return $res; +} + +/** + * ws_addControls + * returns additionnal controls if requested + * usable for 99% of Web Service methods + * + * - Args + * $methodName: is the requested method + * $partner: is the key + * $tbl_name: is the alias_name in the query (sometimes called correlation name) + * null if !getting picture informations + * - Logic + * Access_control is not active: Return + * Key is incorrect: Return 0 = 1 (False condition for MySQL) + * One of Params doesn't match with type of request: return 0 = 1 again + * Access list(id/cat/tag) is converted in expended image-id list + * image-id list: converted to an in-where-clause + * + * The additionnal in-where-clause is return + */ +function ws_addControls( $methodName, &$params, $tbl_name ) +{ + global $conf, $calling_partner_id; + if ( !$conf['ws_access_control'] or !isset($calling_partner_id) ) + { + return '1=1'; // No controls are requested + } + +// Is it an active Partner? + $query = ' +SELECT * FROM '.WEB_SERVICES_ACCESS_TABLE." + WHERE `name` = '$calling_partner_id' + AND NOW() <= end; "; +$result = pwg_query($query); + if ( mysql_num_rows( $result ) == 0 ) + { + return '0=1'; // Unknown partner or Obsolate agreement + } + + $row = mysql_fetch_array($result); + +// Overide general object limit + $params['per_page'] = $row['limit']; + +// Target restrict +// 3 cases: list, cat or tag +// Behind / we could found img-ids, cat-ids or tag-ids + $target = $row['access']; + if ( $target == '') + { + return '1=1'; // No controls are requested + } + list($type, $str_ids) = explode('/',$target); // Find type list + +// (array) 1,2,21,3,22,4,5,9-12,6,11,12,13,2,4,6, + $arr_ids = expand_id_list( explode( ',',$str_ids ) ); + $addings = implode(',', $arr_ids); +// (string) 1,2,3,4,5,6,9,10,11,12,13,21,22, + if ( $type == 'list') + { + return $tbl_name . 'id IN ( ' . $addings . ' ) '; + } + + if ( $type == 'cat' ) + { + $addings = implode(',', get_image_ids_for_cats($arr_ids)); + return $tbl_name . 'id IN ( ' . $addings . ' ) '; + } + + if ( $type == 'tag' ) + { + $addings = implode(',', get_image_ids_for_tags($arr_ids, 'OR')); + return $tbl_name . 'id IN ( ' . $addings . ' ) '; + } + // Unmanaged new type? + return ' 0 = 1 '; // ??? +} + +/** + * returns a "standard" (for our web service) array of sql where clauses that + * filters the images (images table only) + */ +function ws_std_image_sql_filter( $params, $tbl_name='' ) +{ + $clauses = array(); + if ( is_numeric($params['f_min_rate']) ) + { + $clauses[] = $tbl_name.'average_rate>'.$params['f_min_rate']; + } + if ( is_numeric($params['f_max_rate']) ) + { + $clauses[] = $tbl_name.'average_rate<='.$params['f_max_rate']; + } + if ( is_numeric($params['f_min_hit']) ) + { + $clauses[] = $tbl_name.'hit>'.$params['f_min_hit']; + } + if ( is_numeric($params['f_max_hit']) ) + { + $clauses[] = $tbl_name.'hit<='.$params['f_max_hit']; + } + if ( isset($params['f_min_date_posted']) ) + { + $clauses[] = $tbl_name."date_available>='".$params['f_min_date_posted']."'"; + } + if ( isset($params['f_max_date_posted']) ) + { + $clauses[] = $tbl_name."date_available<'".$params['f_max_date_posted']."'"; + } + if ( isset($params['f_min_date_created']) ) + { + $clauses[] = $tbl_name."date_creation>='".$params['f_min_date_created']."'"; + } + if ( isset($params['f_max_date_created']) ) + { + $clauses[] = $tbl_name."date_creation<'".$params['f_max_date_created']."'"; + } + if ( is_numeric($params['f_min_ratio']) ) + { + $clauses[] = $tbl_name.'width/'.$tbl_name.'height>'.$params['f_min_ratio']; + } + if ( is_numeric($params['f_max_ratio']) ) + { + $clauses[] = $tbl_name.'width/'.$tbl_name.'height<='.$params['f_max_ratio']; + } + if ( $params['f_with_thumbnail'] ) + { + $clauses[] = $tbl_name.'tn_ext IS NOT NULL'; + } + return $clauses; +} + +/** + * returns a "standard" (for our web service) ORDER BY sql clause for images + */ +function ws_std_image_sql_order( $params, $tbl_name='' ) +{ + $ret = ''; + if ( empty($params['order']) ) + { + return $ret; + } + $matches = array(); + preg_match_all('/([a-z_]+) *(?:(asc|desc)(?:ending)?)? *(?:, *|$)/i', + $params['order'], $matches); + for ($i=0; $i<count($matches[1]); $i++) + { + switch ($matches[1][$i]) + { + case 'date_created': + $matches[1][$i] = 'date_creation'; break; + case 'date_posted': + $matches[1][$i] = 'date_available'; break; + case 'rand': case 'random': + $matches[1][$i] = 'RAND()'; break; + } + $sortable_fields = array('id', 'file', 'name', 'hit', 'average_rate', + 'date_creation', 'date_available', 'RAND()' ); + if ( in_array($matches[1][$i], $sortable_fields) ) + { + if (!empty($ret)) + $ret .= ', '; + if ($matches[1][$i] != 'RAND()' ) + { + $ret .= $tbl_name; + } + $ret .= $matches[1][$i]; + $ret .= ' '.$matches[2][$i]; + } + } + return $ret; +} + +/** + * returns an array map of urls (thumb/element) for image_row - to be returned + * in a standard way by different web service methods + */ +function ws_std_get_urls($image_row) +{ + $ret = array( + 'tn_url' => get_thumbnail_url($image_row), + 'element_url' => get_element_url($image_row) + ); + global $user; + if ($user['enabled_high'] and $image_row['has_high'] ) + { + $ret['high_url'] = get_high_url($image_row); + } + return $ret; +} + +/** + * returns an array of image attributes that are to be encoded as xml attributes + * instead of xml elements + */ +function ws_std_get_image_xml_attributes() +{ + return array( + 'id','tn_url','element_url','high_url', 'file','width','height','hit' + ); +} + +/** + * returns PWG version (web service method) + */ +function ws_getVersion($params, &$service) +{ + global $conf; + if ($conf['show_version']) + return PHPWG_VERSION; + else + return new PwgError(403, 'Forbidden'); +} + + +/** + * returns images per category (web service method) + */ +function ws_categories_getImages($params, &$service) +{ + @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php'); + global $user, $conf; + + $images = array(); + + //------------------------------------------------- get the related categories + $where_clauses = array(); + foreach($params['cat_id'] as $cat_id) + { + $cat_id = (int)$cat_id; + if ($cat_id<=0) + continue; + if ($params['recursive']) + { + $where_clauses[] = 'uppercats REGEXP \'(^|,)'.$cat_id.'(,|$)\''; + } + else + { + $where_clauses[] = 'id='.$cat_id; + } + } + if (!empty($where_clauses)) + { + $where_clauses = array( '('. + implode(' + OR ', $where_clauses) . ')' + ); + } + $where_clauses[] = get_sql_condition_FandF( + array('forbidden_categories' => 'id'), + NULL, true + ); + + $query = ' +SELECT id, name, permalink, image_order + FROM '.CATEGORIES_TABLE.' + WHERE '. implode(' + AND ', $where_clauses); + $result = pwg_query($query); + $cats = array(); + while ($row = mysql_fetch_assoc($result)) + { + $row['id'] = (int)$row['id']; + $cats[ $row['id'] ] = $row; + } + + //-------------------------------------------------------- get the images + if ( !empty($cats) ) + { + $where_clauses = ws_std_image_sql_filter( $params, 'i.' ); + $where_clauses[] = 'category_id IN (' + .implode(',', array_keys($cats) ) + .')'; + $where_clauses[] = get_sql_condition_FandF( array( + 'visible_images' => 'i.id' + ), null, true + ); + $where_clauses[] = ws_addControls( 'categories.getImages', $params, 'i.' ); + + $order_by = ws_std_image_sql_order($params, 'i.'); + if ( empty($order_by) + and count($params['cat_id'])==1 + and isset($cats[ $params['cat_id'][0] ]['image_order']) + ) + { + $order_by = $cats[ $params['cat_id'][0] ]['image_order']; + } + $order_by = empty($order_by) ? $conf['order_by'] : 'ORDER BY '.$order_by; + + $query = ' +SELECT i.*, GROUP_CONCAT(category_id) cat_ids + FROM '.IMAGES_TABLE.' i + INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON i.id=image_id + WHERE '. implode(' + AND ', $where_clauses).' +GROUP BY i.id +'.$order_by.' +LIMIT '.$params['per_page']*$params['page'].','.$params['per_page']; + + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $image = array(); + foreach ( array('id', 'width', 'height', 'hit') as $k ) + { + if (isset($row[$k])) + { + $image[$k] = (int)$row[$k]; + } + } + foreach ( array('file', 'name', 'comment') as $k ) + { + $image[$k] = $row[$k]; + } + $image = array_merge( $image, ws_std_get_urls($row) ); + + $image_cats = array(); + foreach ( explode(',', $row['cat_ids']) as $cat_id ) + { + $url = make_index_url( + array( + 'category' => $cats[$cat_id], + ) + ); + $page_url = make_picture_url( + array( + 'category' => $cats[$cat_id], + 'image_id' => $row['id'], + 'image_file' => $row['file'], + ) + ); + array_push( $image_cats, array( + WS_XML_ATTRIBUTES => array ( + 'id' => (int)$cat_id, + 'url' => $url, + 'page_url' => $page_url, + ) + ) + ); + } + + $image['categories'] = new PwgNamedArray( + $image_cats,'category', array('id','url','page_url') + ); + array_push($images, $image); + } + } + + return array( 'images' => + array ( + WS_XML_ATTRIBUTES => + array( + 'page' => $params['page'], + 'per_page' => $params['per_page'], + 'count' => count($images) + ), + WS_XML_CONTENT => new PwgNamedArray($images, 'image', + ws_std_get_image_xml_attributes() ) + ) + ); +} + + +/** + * returns a list of categories (web service method) + */ +function ws_categories_getList($params, &$service) +{ + global $user,$conf; + + $where = array(); + + if (!$params['recursive']) + { + if ($params['cat_id']>0) + $where[] = '(id_uppercat='.(int)($params['cat_id']).' + OR id='.(int)($params['cat_id']).')'; + else + $where[] = 'id_uppercat IS NULL'; + } + else if ($params['cat_id']>0) + { + $where[] = 'uppercats REGEXP \'(^|,)'. + (int)($params['cat_id']) + .'(,|$)\''; + } + + if ($params['public']) + { + $where[] = 'status = "public"'; + $where[] = 'visible = "true"'; + $where[]= 'user_id='.$conf['guest_id']; + } + else + { + $where[]= 'user_id='.$user['id']; + } + + $query = ' +SELECT id, name, permalink, uppercats, global_rank, + nb_images, count_images AS total_nb_images, + date_last, max_date_last, count_categories AS nb_categories + FROM '.CATEGORIES_TABLE.' + INNER JOIN '.USER_CACHE_CATEGORIES_TABLE.' ON id=cat_id + WHERE '. implode(' + AND ', $where); + + $result = pwg_query($query); + + $cats = array(); + while ($row = mysql_fetch_assoc($result)) + { + $row['url'] = make_index_url( + array( + 'category' => $row + ) + ); + foreach( array('id','nb_images','total_nb_images','nb_categories') as $key) + { + $row[$key] = (int)$row[$key]; + } + array_push($cats, $row); + } + usort($cats, 'global_rank_compare'); + return array( + 'categories' => + new PwgNamedArray($cats,'category', + array('id','url','nb_images','total_nb_images','nb_categories','date_last','max_date_last') + ) + ); +} + + +/** + * returns detailed information for an element (web service method) + */ +function ws_images_addComment($params, &$service) +{ + if (!$service->isPost()) + { + return new PwgError(405, "This method requires HTTP POST"); + } + $params['image_id'] = (int)$params['image_id']; + $query = ' +SELECT DISTINCT image_id + FROM '.IMAGE_CATEGORY_TABLE.' INNER JOIN '.CATEGORIES_TABLE.' ON category_id=id + WHERE commentable="true" + AND image_id='.$params['image_id']. + get_sql_condition_FandF( + array( + 'forbidden_categories' => 'id', + 'visible_categories' => 'id', + 'visible_images' => 'image_id' + ), + ' AND' + ); + if ( !mysql_num_rows( pwg_query( $query ) ) ) + { + return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id"); + } + + include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php'); + + $comm = array( + 'author' => trim( stripslashes($params['author']) ), + 'content' => trim( stripslashes($params['content']) ), + 'image_id' => $params['image_id'], + ); + + include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php'); + + $comment_action = insert_user_comment( + $comm, $params['key'], $infos + ); + + switch ($comment_action) + { + case 'reject': + array_push($infos, l10n('comment_not_added') ); + return new PwgError(403, implode("\n", $infos) ); + case 'validate': + case 'moderate': + $ret = array( + 'id' => $comm['id'], + 'validation' => $comment_action=='validate', + ); + return new PwgNamedStruct( + 'comment', + $ret, + null, array() + ); + default: + return new PwgError(500, "Unknown comment action ".$comment_action ); + } +} + +/** + * returns detailed information for an element (web service method) + */ +function ws_images_getInfo($params, &$service) +{ + @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php'); + global $user, $conf; + $params['image_id'] = (int)$params['image_id']; + if ( $params['image_id']<=0 ) + { + return new PwgError(WS_ERR_INVALID_PARAM, "Invalid image_id"); + } + + $query=' +SELECT * FROM '.IMAGES_TABLE.' + WHERE id='.$params['image_id']. + get_sql_condition_FandF( + array('visible_images' => 'id'), + ' AND' + ).' AND '. + ws_addControls( 'images.getInfo', $params, '' ).' +LIMIT 1;'; + + $image_row = mysql_fetch_assoc(pwg_query($query)); + if ($image_row==null) + { + return new PwgError(404, "image_id not found"); + } + $image_row = array_merge( $image_row, ws_std_get_urls($image_row) ); + + //-------------------------------------------------------- related categories + $query = ' +SELECT id, name, permalink, uppercats, global_rank, commentable + FROM '.IMAGE_CATEGORY_TABLE.' + INNER JOIN '.CATEGORIES_TABLE.' ON category_id = id + WHERE image_id = '.$image_row['id']. + get_sql_condition_FandF( + array( 'forbidden_categories' => 'category_id' ), + ' AND' + ).' +;'; + $result = pwg_query($query); + $is_commentable = false; + $related_categories = array(); + while ($row = mysql_fetch_assoc($result)) + { + if ($row['commentable']=='true') + { + $is_commentable = true; + } + unset($row['commentable']); + $row['url'] = make_index_url( + array( + 'category' => $row + ) + ); + + $row['page_url'] = make_picture_url( + array( + 'image_id' => $image_row['id'], + 'image_file' => $image_row['file'], + 'category' => $row + ) + ); + $row['id']=(int)$row['id']; + array_push($related_categories, $row); + } + usort($related_categories, 'global_rank_compare'); + if ( empty($related_categories) ) + { + return new PwgError(401, 'Access denied'); + } + + //-------------------------------------------------------------- related tags + $related_tags = get_common_tags( array($image_row['id']), -1 ); + foreach( $related_tags as $i=>$tag) + { + $tag['url'] = make_index_url( + array( + 'tags' => array($tag) + ) + ); + $tag['page_url'] = make_picture_url( + array( + 'image_id' => $image_row['id'], + 'image_file' => $image_row['file'], + 'tags' => array($tag), + ) + ); + unset($tag['counter']); + $tag['id']=(int)$tag['id']; + $related_tags[$i]=$tag; + } + //------------------------------------------------------------- related rates + $query = ' +SELECT COUNT(rate) AS count + , ROUND(AVG(rate),2) AS average + , ROUND(STD(rate),2) AS stdev + FROM '.RATE_TABLE.' + WHERE element_id = '.$image_row['id'].' +;'; + $rating = mysql_fetch_assoc(pwg_query($query)); + $rating['count'] = (int)$rating['count']; + + //---------------------------------------------------------- related comments + $related_comments = array(); + + $where_comments = 'image_id = '.$image_row['id']; + if ( !is_admin() ) + { + $where_comments .= ' + AND validated="true"'; + } + + $query = ' +SELECT COUNT(id) nb_comments + FROM '.COMMENTS_TABLE.' + WHERE '.$where_comments; + list($nb_comments) = array_from_query($query, 'nb_comments'); + $nb_comments = (int)$nb_comments; + + if ( $nb_comments>0 and $params['comments_per_page']>0 ) + { + $query = ' +SELECT id, date, author, content + FROM '.COMMENTS_TABLE.' + WHERE '.$where_comments.' + ORDER BY date + LIMIT '.$params['comments_per_page']*(int)$params['comments_page']. + ','.$params['comments_per_page']; + + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $row['id']=(int)$row['id']; + array_push($related_comments, $row); + } + } + + $comment_post_data = null; + if ($is_commentable and + (!is_a_guest() + or (is_a_guest() and $conf['comments_forall'] ) + ) + ) + { + include_once(PHPWG_ROOT_PATH.'include/functions_comment.inc.php'); + $comment_post_data['author'] = $user['username']; + $comment_post_data['key'] = get_comment_post_key($params['image_id']); + } + + $ret = $image_row; + foreach ( array('id','width','height','hit','filesize') as $k ) + { + if (isset($ret[$k])) + { + $ret[$k] = (int)$ret[$k]; + } + } + foreach ( array('path', 'storage_category_id') as $k ) + { + unset($ret[$k]); + } + + $ret['rates'] = array( WS_XML_ATTRIBUTES => $rating ); + $ret['categories'] = new PwgNamedArray($related_categories, 'category', array('id','url', 'page_url') ); + $ret['tags'] = new PwgNamedArray($related_tags, 'tag', array('id','url_name','url','page_url') ); + if ( isset($comment_post_data) ) + { + $ret['comment_post'] = array( WS_XML_ATTRIBUTES => $comment_post_data ); + } + $ret['comments'] = array( + WS_XML_ATTRIBUTES => + array( + 'page' => $params['comments_page'], + 'per_page' => $params['comments_per_page'], + 'count' => count($related_comments), + 'nb_comments' => $nb_comments, + ), + WS_XML_CONTENT => new PwgNamedArray($related_comments, 'comment', array('id','date') ) + ); + + return new PwgNamedStruct('image',$ret, null, array('name','comment') ); +} + +/** + * returns a list of elements corresponding to a query search + */ +function ws_images_search($params, &$service) +{ + global $page; + $images = array(); + include_once( PHPWG_ROOT_PATH .'include/functions_search.inc.php' ); + include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php'); + + $where_clauses = ws_std_image_sql_filter( $params, 'i.' ); + $order_by = ws_std_image_sql_order($params, 'i.'); + + if ( !empty($order_by) ) + { + global $conf; + $conf['order_by'] = 'ORDER BY '.$order_by; + $page['super_order_by']=1; // quick_search_result might be faster + } + + $search_result = get_quick_search_results($params['query'], + implode(',', $where_clauses) ); + $image_ids = $search_result['items']; + + $image_ids = array_slice($image_ids, + $params['page']*$params['per_page'], + $params['per_page'] ); + + if ( count($image_ids) ) + { + $query = ' +SELECT * FROM '.IMAGES_TABLE.' + WHERE id IN (' + .wordwrap(implode(', ', $image_ids), 80, "\n") + .')'; + + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $image = array(); + foreach ( array('id', 'width', 'height', 'hit') as $k ) + { + if (isset($row[$k])) + { + $image[$k] = (int)$row[$k]; + } + } + foreach ( array('file', 'name', 'comment') as $k ) + { + $image[$k] = $row[$k]; + } + $image = array_merge( $image, ws_std_get_urls($row) ); + array_push($images, $image); + } + + $image_ids = array_flip($image_ids); + usort( + $images, + create_function('$i1,$i2', 'global $image_ids; return $image_ids[$i1["id"]]-$image_ids[$i2["id"]];') + ); + } + + + return array( 'images' => + array ( + WS_XML_ATTRIBUTES => + array( + 'page' => $params['page'], + 'per_page' => $params['per_page'], + 'count' => count($images) + ), + WS_XML_CONTENT => new PwgNamedArray($images, 'image', + ws_std_get_image_xml_attributes() ) + ) + ); +} + +/** + * perform a login (web service method) + */ +function ws_session_login($params, &$service) +{ + global $conf; + + if (!$service->isPost()) + { + return new PwgError(405, "This method requires HTTP POST"); + } + if (try_log_user($params['username'], $params['password'],false)) + { + return true; + } + return new PwgError(999, 'Invalid username/password'); +} + + +/** + * performs a logout (web service method) + */ +function ws_session_logout($params, &$service) +{ + global $user, $conf; + if (!is_a_guest()) + { + $_SESSION = array(); + session_unset(); + session_destroy(); + setcookie(session_name(),'',0, + ini_get('session.cookie_path'), + ini_get('session.cookie_domain') + ); + setcookie($conf['remember_me_name'], '', 0, cookie_path()); + } + return true; +} + +function ws_session_getStatus($params, &$service) +{ + global $user; + $res = array(); + $res['username'] = is_a_guest() ? 'guest' : $user['username']; + foreach ( array('status', 'template', 'theme', 'language') as $k ) + { + $res[$k] = $user[$k]; + } + $res['charset'] = get_pwg_charset(); + return $res; +} + + +/** + * returns a list of tags (web service method) + */ +function ws_tags_getList($params, &$service) +{ + $tags = get_available_tags(); + if ($params['sort_by_counter']) + { + usort($tags, create_function('$a,$b', 'return -$a["counter"]+$b["counter"];') ); + } + else + { + usort($tags, 'name_compare'); + } + for ($i=0; $i<count($tags); $i++) + { + $tags[$i]['id'] = (int)$tags[$i]['id']; + $tags[$i]['counter'] = (int)$tags[$i]['counter']; + $tags[$i]['url'] = make_index_url( + array( + 'section'=>'tags', + 'tags'=>array($tags[$i]) + ) + ); + } + return array('tags' => new PwgNamedArray($tags, 'tag', array('id','url_name','url', 'counter' )) ); +} + + +/** + * returns a list of images for tags (web service method) + */ +function ws_tags_getImages($params, &$service) +{ + @include_once(PHPWG_ROOT_PATH.'include/functions_picture.inc.php'); + global $conf; + + // first build all the tag_ids we are interested in + $params['tag_id'] = array_map( 'intval',$params['tag_id'] ); + $tags = find_tags($params['tag_id'], $params['tag_url_name'], $params['tag_name']); + $tags_by_id = array(); + foreach( $tags as $tag ) + { + $tags['id'] = (int)$tag['id']; + $tags_by_id[ $tag['id'] ] = $tag; + } + unset($tags); + $tag_ids = array_keys($tags_by_id); + + + $image_ids = array(); + $image_tag_map = array(); + + if ( !empty($tag_ids) ) + { // build list of image ids with associated tags per image + if ($params['tag_mode_and']) + { + $image_ids = get_image_ids_for_tags( $tag_ids ); + } + else + { + $query = ' +SELECT image_id, GROUP_CONCAT(tag_id) tag_ids + FROM '.IMAGE_TAG_TABLE.' + WHERE tag_id IN ('.implode(',',$tag_ids).') + GROUP BY image_id'; + $result = pwg_query($query); + while ( $row=mysql_fetch_assoc($result) ) + { + $row['image_id'] = (int)$row['image_id']; + array_push( $image_ids, $row['image_id'] ); + $image_tag_map[ $row['image_id'] ] = explode(',', $row['tag_ids']); + } + } + } + + $images = array(); + if ( !empty($image_ids)) + { + $where_clauses = ws_std_image_sql_filter($params); + $where_clauses[] = get_sql_condition_FandF( + array + ( + 'forbidden_categories' => 'category_id', + 'visible_categories' => 'category_id', + 'visible_images' => 'i.id' + ), + '', true + ); + $where_clauses[] = 'id IN ('.implode(',',$image_ids).')'; + $where_clauses[] = ws_addControls( 'tags.getImages', $params, 'i.' ); + + $order_by = ws_std_image_sql_order($params); + if (empty($order_by)) + { + $order_by = $conf['order_by']; + } + else + { + $order_by = 'ORDER BY '.$order_by; + } + + $query = ' +SELECT DISTINCT i.* FROM '.IMAGES_TABLE.' i + INNER JOIN '.IMAGE_CATEGORY_TABLE.' ON i.id=image_id + WHERE '. implode(' + AND ', $where_clauses).' +'.$order_by.' +LIMIT '.$params['per_page']*$params['page'].','.$params['per_page']; + + $result = pwg_query($query); + while ($row = mysql_fetch_assoc($result)) + { + $image = array(); + foreach ( array('id', 'width', 'height', 'hit') as $k ) + { + if (isset($row[$k])) + { + $image[$k] = (int)$row[$k]; + } + } + foreach ( array('file', 'name', 'comment') as $k ) + { + $image[$k] = $row[$k]; + } + $image = array_merge( $image, ws_std_get_urls($row) ); + + $image_tag_ids = ($params['tag_mode_and']) ? $tag_ids : $image_tag_map[$image['id']]; + $image_tags = array(); + foreach ($image_tag_ids as $tag_id) + { + $url = make_index_url( + array( + 'section'=>'tags', + 'tags'=> array($tags_by_id[$tag_id]) + ) + ); + $page_url = make_picture_url( + array( + 'section'=>'tags', + 'tags'=> array($tags_by_id[$tag_id]), + 'image_id' => $row['id'], + 'image_file' => $row['file'], + ) + ); + array_push($image_tags, array( + 'id' => (int)$tag_id, + 'url' => $url, + 'page_url' => $page_url, + ) + ); + } + $image['tags'] = new PwgNamedArray($image_tags, 'tag', + array('id','url_name','url','page_url') + ); + array_push($images, $image); + } + } + + return array( 'images' => + array ( + WS_XML_ATTRIBUTES => + array( + 'page' => $params['page'], + 'per_page' => $params['per_page'], + 'count' => count($images) + ), + WS_XML_CONTENT => new PwgNamedArray($images, 'image', + ws_std_get_image_xml_attributes() ) + ) + ); +} + + +/** + * expand_id_list($ids) convert a human list expression to a full ordered list + * example : expand_id_list( array(5,2-3,2) ) returns array( 2, 3, 5) + * */ +function expand_id_list($ids) +{ + $tid = array(); + foreach ( $ids as $id ) + { + if ( is_numeric($id) ) + { + $tid[] = (int) $id; + } + else + { + $range = explode( '-', $id ); + if ( is_numeric($range[0]) and is_numeric($range[1]) ) + { + $from = min($range[0],$range[1]); + $to = max($range[0],$range[1]); + for ($i = $from; $i <= $to; $i++) + { + $tid[] = (int) $i; + } + } + } + } + $result = array_unique ($tid); // remove duplicates... + sort ($result); + return $result; +} + + +/** + * converts a cat-ids array in image-ids array + * FIXME Function which should already exist somewhere else + * */ +function get_image_ids_for_cats($cat_ids) +{ + $cat_list = implode(',', $cat_ids); + $ret_ids = array(); + $query = ' + SELECT DISTINCT image_id + FROM '.IMAGE_CATEGORY_TABLE.' + WHERE category_id in ('.$cat_list.') + ;'; + return array_from_query($query, 'image_id'); +} + +?> diff --git a/BSF/include/ws_protocols/index.php b/BSF/include/ws_protocols/index.php new file mode 100644 index 000000000..c15b15795 --- /dev/null +++ b/BSF/include/ws_protocols/index.php @@ -0,0 +1,30 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +// Recursive call +$url = '../'; +header( 'Request-URI: '.$url ); +header( 'Content-Location: '.$url ); +header( 'Location: '.$url ); +exit(); +?> diff --git a/BSF/include/ws_protocols/json_encoder.php b/BSF/include/ws_protocols/json_encoder.php new file mode 100644 index 000000000..8c2d7b0a0 --- /dev/null +++ b/BSF/include/ws_protocols/json_encoder.php @@ -0,0 +1,87 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + + +#_____________________ PHP 5.2 +if (! function_exists('json_encode')) { + function json_encode($data) { + switch (gettype($data)) { + case 'boolean': + return ($data ? 'true' : 'false'); + case 'null': + case 'NULL': + return 'null'; + case 'integer': + case 'double': + return $data; + case 'string': + return '"'. str_replace(array("\\",'"',"/","\n","\r","\t"), array("\\\\",'\"',"\\/","\\n","\\r","\\t"), $data) .'"'; + case 'object': + case 'array': + if ($data === array()) return '[]'; # empty array + if (range(0, count($data) - 1) !== array_keys($data) ) { # string keys, unordered, non-incremental keys, .. - whatever, make object + $out = "\n".'{'; + foreach($data as $key => $value) { + $out .= json_encode((string) $key) . ':' . json_encode($value) . ','; + } + $out = substr($out, 0, -1) . "\n". '}'; + }else{ + # regular array + $out = "\n".'[' . join("\n".',', array_map('json_encode', $data)) ."\n".']'; + } + return $out; + } + } +} + +class PwgJsonEncoder extends PwgResponseEncoder +{ + function encodeResponse($response) + { + $respClass = strtolower( get_class($response) ); + if ($respClass=='pwgerror') + { + return json_encode( + array( + 'stat' => 'fail', + 'err' => $response->code(), + 'message' => $response->message(), + ) + ); + } + parent::flattenResponse($response); + return json_encode( + array( + 'stat' => 'ok', + 'result' => $response, + ) + ); + } + + function getContentType() + { + return 'text/plain'; + } +} + +?> diff --git a/BSF/include/ws_protocols/php_encoder.php b/BSF/include/ws_protocols/php_encoder.php new file mode 100644 index 000000000..ce9afd3e6 --- /dev/null +++ b/BSF/include/ws_protocols/php_encoder.php @@ -0,0 +1,54 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +class PwgSerialPhpEncoder extends PwgResponseEncoder +{ + function encodeResponse($response) + { + $respClass = strtolower( get_class($response) ); + if ($respClass=='pwgerror') + { + return serialize( + array( + 'stat' => 'fail', + 'err' => $response->code(), + 'message' => $response->message(), + ) + ); + } + parent::flattenResponse($response); + return serialize( + array( + 'stat' => 'ok', + 'result' => $response + ) + ); + } + + function getContentType() + { + return 'text/plain'; + } +} + +?> diff --git a/BSF/include/ws_protocols/rest_encoder.php b/BSF/include/ws_protocols/rest_encoder.php new file mode 100644 index 000000000..e057c6427 --- /dev/null +++ b/BSF/include/ws_protocols/rest_encoder.php @@ -0,0 +1,281 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + + +class PwgXmlWriter +{ + var $_indent; + var $_indentStr; + + var $_elementStack; + var $_lastTagOpen; + var $_indentLevel; + + var $_encodedXml; + + function PwgXmlWriter() + { + $this->_elementStack = array(); + $this->_lastTagOpen = false; + $this->_indentLevel = 0; + + $this->_encodedXml = ''; + $this->_indent = true; + $this->_indentStr = "\t"; + } + + function &getOutput() + { + return $this->_encodedXml; + } + + + function start_element($name) + { + $this->_end_prev(false); + if (!empty($this->_elementStack)) + { + $this->_eol_indent(); + } + $this->_indentLevel++; + $this->_indent(); + $this->_output( '<'.$name ); + $this->_lastTagOpen = true; + array_push( $this->_elementStack, $name); + } + + function end_element($x) + { + $close_tag = $this->_end_prev(true); + $name = array_pop( $this->_elementStack ); + if ($close_tag) + { + $this->_indentLevel--; + $this->_indent(); +// $this->_eol_indent(); + $this->_output('</'.$name.">"); + } + } + + function write_content($value) + { + $this->_end_prev(false); + $value = (string)$value; + $this->_output( htmlspecialchars( $value ) ); + } + + function write_cdata($value) + { + $this->_end_prev(false); + $value = (string)$value; + $this->_output( + '<![CDATA[' + . str_replace(']]>', ']]>', $value) + . ']]>' ); + } + + function write_attribute($name, $value) + { + $this->_output(' '.$name.'="'.$this->encode_attribute($value).'"'); + } + + function encode_attribute($value) + { + return htmlspecialchars( (string)$value); + } + + function _end_prev($done) + { + $ret = true; + if ($this->_lastTagOpen) + { + if ($done) + { + $this->_indentLevel--; + $this->_output( ' />' ); + //$this->_eol_indent(); + $ret = false; + } + else + { + $this->_output( '>' ); + } + $this->_lastTagOpen = false; + } + return $ret; + } + + function _eol_indent() + { + if ($this->_indent) + $this->_output("\n"); + } + + function _indent() + { + if ($this->_indent and + $this->_indentLevel > count($this->_elementStack) ) + { + $this->_output( + str_repeat( $this->_indentStr, count($this->_elementStack) ) + ); + } + } + + function _output($raw_content) + { + $this->_encodedXml .= $raw_content; + } +} + +class PwgRestEncoder extends PwgResponseEncoder +{ + function encodeResponse($response) + { + $respClass = strtolower( get_class($response) ); + if ($respClass=='pwgerror') + { + $ret = '<?xml version="1.0"?> +<rsp stat="fail"> + <err code="'.$response->code().'" msg="'.htmlspecialchars($response->message()).'" /> +</rsp>'; + return $ret; + } + + $this->_writer = new PwgXmlWriter(); + $this->encode($response); + $ret = $this->_writer->getOutput(); + $ret = '<?xml version="1.0" encoding="'.get_pwg_charset().'" ?> +<rsp stat="ok"> +'.$ret.' +</rsp>'; + + return $ret; + } + + function getContentType() + { + return 'text/xml'; + } + + function encode_array($data, $itemName, $xml_attributes=array()) + { + foreach ($data as $item) + { + $this->_writer->start_element( $itemName ); + $this->encode($item, $xml_attributes); + $this->_writer->end_element( $itemName ); + } + } + + function encode_struct($data, $skip_underscore, $xml_attributes=array()) + { + foreach ($data as $name => $value) + { + if (is_numeric($name)) + continue; + if ($skip_underscore and $name[0]=='_') + continue; + if ( is_null($value) ) + continue; // null means we dont put it + if ( $name==WS_XML_ATTRIBUTES) + { + foreach ($value as $attr_name => $attr_value) + { + $this->_writer->write_attribute($attr_name, $attr_value); + } + unset($data[$name]); + } + else if ( isset($xml_attributes[$name]) ) + { + $this->_writer->write_attribute($name, $value); + unset($data[$name]); + } + } + + foreach ($data as $name => $value) + { + if (is_numeric($name)) + continue; + if ($skip_underscore and $name[0]=='_') + continue; + if ( is_null($value) ) + continue; // null means we dont put it + if ($name!=WS_XML_CONTENT) + $this->_writer->start_element($name); + $this->encode($value); + if ($name!=WS_XML_CONTENT) + $this->_writer->end_element($name); + } + } + + function encode($data, $xml_attributes=array() ) + { + switch (gettype($data)) + { + case 'null': + case 'NULL': + $this->_writer->write_content(''); + break; + case 'boolean': + $this->_writer->write_content($data ? '1' : '0'); + break; + case 'integer': + case 'double': + $this->_writer->write_content($data); + break; + case 'string': + $this->_writer->write_content($data); + break; + case 'array': + $is_array = range(0, count($data) - 1) === array_keys($data); + if ($is_array) + { + $this->encode_array($data, 'item' ); + } + else + { + $this->encode_struct($data, false, $xml_attributes); + } + break; + case 'object': + switch ( strtolower(get_class($data)) ) + { + case 'pwgnamedarray': + $this->encode_array($data->_content, $data->_itemName, $data->_xmlAttributes); + break; + case 'pwgnamedstruct': + $this->encode_array( array($data->_content), $data->_name, $data->_xmlAttributes); + break; + default: + $this->encode_struct(get_object_vars($data), true); + break; + } + break; + default: + trigger_error("Invalid type ". gettype($data)." ".get_class($data), E_USER_WARNING ); + } + } +} + +?> diff --git a/BSF/include/ws_protocols/rest_handler.php b/BSF/include/ws_protocols/rest_handler.php new file mode 100644 index 000000000..c9c8ad9b0 --- /dev/null +++ b/BSF/include/ws_protocols/rest_handler.php @@ -0,0 +1,57 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +class PwgRestRequestHandler +{ + function handleRequest(&$service) + { + $params = array(); + + $param_array = $service->isPost() ? $_POST : $_GET; + foreach ($param_array as $name => $value) + { + if ($name=='format' or $name=='partner') + continue; // ignore - special keys + if ($name=='method') + { + $method = $value; + } + else + { + $params[$name]=$value; + } + } + + if ( empty($method) ) + { + $service->sendResponse( + new PwgError(400, 'Missing "method" name') + ); + return; + } + $resp = $service->invoke($method, $params); + $service->sendResponse($resp); + } +} + +?> diff --git a/BSF/include/ws_protocols/xmlrpc_encoder.php b/BSF/include/ws_protocols/xmlrpc_encoder.php new file mode 100644 index 000000000..26f0f510e --- /dev/null +++ b/BSF/include/ws_protocols/xmlrpc_encoder.php @@ -0,0 +1,115 @@ +<?php +// +-----------------------------------------------------------------------+ +// | Piwigo - a PHP based picture gallery | +// +-----------------------------------------------------------------------+ +// | Copyright(C) 2008 Piwigo Team http://piwigo.org | +// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net | +// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick | +// +-----------------------------------------------------------------------+ +// | This program is free software; you can redistribute it and/or modify | +// | it under the terms of the GNU General Public License as published by | +// | the Free Software Foundation | +// | | +// | This program is distributed in the hope that it will be useful, but | +// | WITHOUT ANY WARRANTY; without even the implied warranty of | +// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | +// | General Public License for more details. | +// | | +// | You should have received a copy of the GNU General Public License | +// | along with this program; if not, write to the Free Software | +// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, | +// | USA. | +// +-----------------------------------------------------------------------+ + +function xmlrpc_encode($data) +{ + switch (gettype($data)) + { + case 'boolean': + return '<boolean>'.($data ? '1' : '0').'</boolean>'; + case 'integer': + return '<int>'.$data.'</int>'; + case 'double': + return '<double>'.$data.'</double>'; + case 'string': + return '<string>'.htmlspecialchars($data).'</string>'; + case 'object': + case 'array': + $is_array = range(0, count($data) - 1) === array_keys($data); + if ($is_array) + { + $return = '<array><data>'."\n"; + foreach ($data as $item) + { + $return .= ' <value>'.xmlrpc_encode($item)."</value>\n"; + } + $return .= '</data></array>'; + } + else + { + $return = '<struct>'."\n"; + foreach ($data as $name => $value) + { + $name = htmlspecialchars($name); + $return .= " <member><name>$name</name><value>"; + $return .= xmlrpc_encode($value)."</value></member>\n"; + } + $return .= '</struct>'; + } + return $return; + } +} + +class PwgXmlRpcEncoder extends PwgResponseEncoder +{ + function encodeResponse($response) + { + $respClass = strtolower( get_class($response) ); + if ($respClass=='pwgerror') + { + $code = $response->code(); + $msg = htmlspecialchars($response->message()); + $ret = <<<EOD +<methodResponse> + <fault> + <value> + <struct> + <member> + <name>faultCode</name> + <value><int>{$code}</int></value> + </member> + <member> + <name>faultString</name> + <value><string>{$msg}</string></value> + </member> + </struct> + </value> + </fault> +</methodResponse> +EOD; + return $ret; + } + + parent::flattenResponse($response); + $ret = xmlrpc_encode($response); + $ret = <<<EOD +<methodResponse> + <params> + <param> + <value> + $ret + </value> + </param> + </params> +</methodResponse> +EOD; + return $ret; + } + + function getContentType() + { + return 'text/xml'; + } +} + +?> |