$name) { if (is_string($func)) $this->register_modifier($name, $func); else $this->register_modifier($name, $name); } foreach (get_class_methods('Rendu_Modifiers') as $name) { $this->register_modifier($name, array('Rendu_Modifiers', $name)); } foreach (Rendu_Modifiers::$modifiers_aliases as $name=>$func) { $this->register_modifier($name, array('Rendu_Modifiers', $func)); } } public function __construct($journal, $force_custom_skin = false) { if (empty($journal->id)) return false; $this->_registerDefaultModifiers(); Rendu_Modifiers::$journal = $journal->get('id'); $this->id = $journal->get('id'); $this->journal = $journal->getAll(); if ($force_custom_skin) { $this->journal['visuel'] = self::CUSTOM_SKIN; } $this->assign('url_hebergeur', LENCRIER_HOME_URL); $this->assign('nom_hebergeur', LENCRIER_HOME_NAME); $this->assign('url_icone_hebergeur', LENCRIER_FAVICON); $this->assign('titre_journal', $journal->get('titre')); $this->assign('texte_journal', $journal->get('texte')); $this->assign('url_journal', $journal->get('url')); $this->assign('url_rss', $journal->get('url') . 'backend/'); $this->assign('forum', $journal->get('forum') ? $journal->get('url') . 'forum/' : ''); $this->assign('abonnement', $journal->get('abonnement') ? $journal->get('url') . 'abonnement/' : ''); $this->assign('contact', $journal->get('contact') ? $journal->get('url') . 'contact/' : ''); $this->assign('url_formulaire_forum', $journal->get('url') . 'forum/post/'); $this->assign('url_formulaire_contact', $journal->get('url') . 'contact/post/'); $this->assign('url_css', $this->getCssURL() . '?2013-09'); $this->assign('url_theme', $this->getSkinURL()); $this->assign('url_documents', utils::getJournalDatasURL($this->id, 'documents')); $this->assign('url_images', utils::getJournalDatasURL($this->id, 'documents') . 'images/'); $this->template_path = LENCRIER_ROOT; } public function getCssURL() { if (strpos($this->journal['visuel'], self::CUSTOM_SKIN) === 0) { return utils::getJournalDatasURL($this->id, 'documents') . 'skel_style.css'; } else { return 'http://' . LENCRIER_ADMIN_HOST . '/datas/skins/' . $this->journal['visuel'] . '/style.css'; } } public function getSkinURL() { if (strpos($this->journal['visuel'], self::CUSTOM_SKIN) === 0) { return utils::getJournalDatasURL($this->id, 'documents'); } else { return 'http://' . LENCRIER_ADMIN_HOST . '/datas/skins/' . $this->journal['visuel'] . '/'; } } private function _getTemplatePath($file, $force_custom = false) { return self::getTemplatePath($file, $this->journal['visuel'], $this->id, $force_custom); } static public function getTemplatePath($file, $visuel, $id, $force_custom = false) { if (!preg_match('!^[a-z0-9_-]+$!i', $file)) throw new technicalException("Invalid template name: ".$file); if ($visuel == self::CUSTOM_SKIN) { $path = utils::getJournalDatasPath($id, 'documents') . '/skel_' . $file . '.html'; } elseif ($force_custom) { return false; } else { $path = LENCRIER_DATA_ROOT . '/skins/' . $visuel . '/' . $file . '.html'; } if (!file_exists($path)) { $path = LENCRIER_DATA_ROOT . '/skins/' . self::DEFAULT_SKIN . '/' . $file . '.html'; } return str_replace(LENCRIER_ROOT, '', $path); } public function renderFeed() { $this->display('/templates/skel/feed.tpl'); } public function renderHome() { $this->display($this->_getTemplatePath('accueil')); } public function renderContact() { $this->assign('message_envoye', isset($_GET['ok'])); $this->assign('formulaire_contact', $this->fetch('/templates/skel/contact_form.tpl')); $this->display($this->_getTemplatePath('contact')); } public function renderArchive($mois) { $this->assign('mois', strtotime(substr($mois, 0, 4) . '-' . substr($mois, 4, 2) . '-01')); $this->display($this->_getTemplatePath('liste_ecrits')); } public function renderForumList($debut = 0) { $this->assign('debut_liste', $debut); $this->display($this->_getTemplatePath('forum')); } public function renderForumThread($uri) { $this->assign('uri', $uri); $this->display($this->_getTemplatePath('forum_message')); } public function renderEcrit($uri) { $this->assign('uri', $uri); $this->display($this->_getTemplatePath('ecrit')); } public function checkCustom($name) { $path = $this->_getTemplatePath($name, true); return $path && file_exists($this->template_path . $path); } public function renderCustom($name, $opts = array()) { $i = 1; foreach ($opts as $o) { $this->assign('argument_' . $i++, $o); } $this->display($this->_getTemplatePath($name, true)); } public function renderOther($name) { $this->display($this->_getTemplatePath($name)); } protected function processInclude($args) { if (empty($args)) throw new miniSkelMarkupException("Le tag INCLURE demande à préciser le fichier à inclure."); $file = key($args); if (empty($file) || !preg_match('!^[a-z0-9_-]+$!', $file)) throw new miniSkelMarkupException("INCLURE: le nom de fichier ne peut contenir que des caractères alphanumériques."); return 'fetch($this->_getTemplatePath("'.$file.'"), false, true); ?>'; } protected function processVariable($name, $value, $applyDefault, $modifiers, $pre, $post, $context) { $out = 'parent[\''.$name.'\'])) $value = $this->parent[\''.$name.'\'];'; $out.= "\n"; $out.= 'elseif (isset($this->variables[\''.$name.'\'])) $value = $this->variables[\''.$name.'\'];'; $out.= "\n"; $out.= 'else $value = "";'; $out.= "\n"; if ($applyDefault) { $out.= 'if (is_string($value) && trim($value)) $value = htmlspecialchars($value, ENT_QUOTES, \'UTF-8\', false);'; $out.= "\n"; } // We process modifiers foreach ($modifiers as &$modifier) { if (!isset($this->modifiers[$modifier['name']])) { throw new miniSkelMarkupException('Modifieur '.$modifier['name'].' inconnu !'); } $args = 'array($value, '; foreach ($modifier['arguments'] as $arg) { if ($arg == 'debut_liste') $args .= '(isset($this->variables[\'debut_liste\']) ? $this->variables[\'debut_liste\'] : ""), '; else $args .= '"'.str_replace('"', '\\"', $arg).'", '; } $args.= ')'; $out.= '$value = call_user_func_array('.var_export($this->modifiers[$modifier['name']], true).', '.$args.');'; $out.= "\n"; } $out.= 'if ($value === true || trim($value) !== \'\'): ?>'; // Getting pre-content if ($pre) $out .= $this->parseVariables($pre, false, $context); $out .= ''; // Getting post-content if ($post) $out .= $this->parseVariables($post, false, $context); $out .= ''; return $out; } protected function processLoop($loopName, $loopType, $loopCriterias, $loopContent, $preContent, $postContent, $altContent) { $out = ''; $loopStart = ''; $query = $where = $order = ''; $limit = $begin = 0; $separator = ''; if ($loopType == 'ecrits') /////// ECRITS ///////////////////////////////// { $query = 'SELECT e.*, h.texte AS texte FROM ecrits AS e, ecrits_html AS h '; $where = 'WHERE e.journal = "\'.DB::esc($this->id).\'" AND e.id = h.id'; $where.= ' AND e.status = 1'; $allowed_fields = array('id', 'mois', 'titre', 'date', 'uri', 'suivant', 'precedent'); foreach ($loopCriterias as $criteria) { if (isset($criteria['field']) && $criteria['action'] != miniSkel::ACTION_MATCH_FIELD && !in_array($criteria['field'], $allowed_fields)) { throw new miniSkelMarkupException("Critere '".$criteria['field']."' invalide pour la boucle '$loopName'"); } switch ($criteria['action']) { case miniSkel::ACTION_DISPLAY_SEPARATOR: $separator = $criteria['value']; break; case miniSkel::ACTION_ORDER_BY: if (!$order) $order = 'ORDER BY e.'.$criteria['field'].''; else $order .= ', '.$criteria['field'].''; break; case miniSkel::ACTION_ORDER_DESC: if ($order) $order .= ' DESC'; break; case miniSkel::ACTION_LIMIT: $begin = $criteria['begin']; $limit = $criteria['number']; break; case miniSkel::ACTION_MATCH_FIELD_BY_VALUE: if ($criteria['field'] == 'date') { $criteria['value'] = strtotime($criteria['value']); } $where .= ' AND e.'.$criteria['field'].' '.$criteria['comparison'].' "'. DB::esc($criteria['value']) . '"'; break; case miniSkel::ACTION_MATCH_FIELD: if ($criteria['field'] == 'mois') { $where .= ' AND e.mois = "\'.date(\'Ym\', $this->variables[\'mois\']).\'"'; } elseif ($criteria['field'] == 'uri') { $where .= ' AND e.uri = "\'.DB::esc($this->variables[\'uri\']).\'"'; $limit = 1; } elseif ($criteria['field'] == 'suivant') { $where .= ' AND e.date > "\'.DB::esc($this->parent[\'date\']).\'"'; $order = 'ORDER BY e.date ASC'; $limit = 1; } elseif ($criteria['field'] == 'precedent') { $where .= ' AND e.date < "\'.DB::esc($this->parent[\'date\']).\'"'; $order = 'ORDER BY e.date DESC'; $limit = 1; } break; default: break; } } if (trim($loopContent)) { $loopStart .= '$row[\'url\'] = utils::getEcritUrl($this->id, $row); '; $loopStart .= '$row[\'intro\'] = Rendu_Modifiers::couper(html_entity_decode(strip_tags($row[\'texte\']), ENT_COMPAT, \'UTF-8\'), 600, \'\');'; } } elseif ($loopType == 'forums') /////// FORUMS ///////////////////////////////// { if (trim($loopContent)) { $query = 'SELECT f.*, t.texte AS texte FROM forums AS f, forums_textes AS t '; $where = 'WHERE f.journal = "\'.DB::esc($this->id).\'" AND f.id = t.id'; $where.= ' AND f.status = 1 '; } else { $query = 'SELECT id FROM forums AS f '; $where = 'WHERE journal = "\'.DB::esc($this->id).\'" AND f.status = 1 '; } $allowed_fields = array('id', 'nom', 'titre', 'date', 'reponses', 'parent', 'dernier_message', 'uri'); foreach ($loopCriterias as $criteria) { if (isset($criteria['field']) && !in_array($criteria['field'], $allowed_fields)) { throw new miniSkelException("Le critère '".$criteria['field']."' est inconnu dans les boucles FORUMS."); } switch ($criteria['action']) { case miniSkel::ACTION_DISPLAY_SEPARATOR: $separator = $criteria['value']; break; case miniSkel::ACTION_ORDER_BY: if (!$order) $order = 'ORDER BY f.'.$criteria['field'].''; else $order .= ', '.$criteria['field'].''; break; case miniSkel::ACTION_ORDER_DESC: if ($order) $order .= ' DESC'; break; case miniSkel::ACTION_LIMIT: $begin = $criteria['begin']; $limit = $criteria['number']; break; case miniSkel::ACTION_MATCH_FIELD_BY_VALUE: $where .= ' AND f.'.$criteria['field'].' '.$criteria['comparison'].' "'. DB::esc($criteria['value']) . '"'; break; case miniSkel::ACTION_MATCH_FIELD: if ($criteria['field'] == 'parent') { $where .= ' AND parent = \'.(int)$this->parent[\'id\'].\''; } elseif ($criteria['field'] == 'uri') { $where .= ' AND uri = "\'.DB::esc($this->variables[\'uri\']).\'"'; $limit = 1; } break; default: break; } } if (trim($loopContent)) { $loopStart = '$row[\'url\'] = utils::getForumMessageUrl($this->id, $row[\'uri\']);'; } } elseif ($loopType == 'mois') { $query = 'SELECT mois FROM ecrits '; $where = 'WHERE journal = "\'.DB::esc($this->id).\'" AND status = 1'; $order = 'GROUP BY mois ORDER BY mois'; foreach ($loopCriterias as $criteria) { switch ($criteria['action']) { case miniSkel::ACTION_DISPLAY_SEPARATOR: $separator = $criteria['value']; break; case miniSkel::ACTION_ORDER_DESC: if ($order) $order .= ' DESC'; break; /* case miniSkel::ACTION_MATCH_FIELD_BY_VALUE: { if ($criteria['field'] != 'mois' || !is_numeric($criteria['value'])) break; $where .= ' AND '.$criteria['field'].' '.$criteria['comparison'].' "'. DB::esc($criteria['value']) . '"'; break; } */ default: break; } } $loopStart .= 'list($y, $m) = str_split($row[\'mois\'], 4); '; $loopStart .= '$row[\'date\'] = strtotime($y.\'-\'.$m.\'-01\');'; $loopStart .= "\n"; $loopStart .= '$row[\'url\'] = $this->journal[\'url\'] . $y . \'/\' . $m . \'/\';'; } else { throw new miniSkelMarkupException("Le type de boucle '".$loopType."' est inconnu."); } $query .= $where . ' ' . $order; if (!$limit) $limit = 100; if ($limit) { $query .= ' LIMIT '.(is_numeric($begin) ? (int) $begin : '\'.(isset($this->variables[\'debut_liste\']) ? (int)$this->variables[\'debut_liste\'] : 0).\'').','.(int)$limit; } $hash = sha1(uniqid(mt_rand(), true)); $out .= "parent =& $this->_vars[$parent_hash]; $result_'.$hash.' = DB::query(\''.$query.'\'); $nb_rows = DB::numRows($result_'.$hash.');'; $out .= "\n"; $out .= '$this->_vars[\''.$hash.'\'] = array(\'_self_hash\' => \''.$hash.'\', \'_parent_hash\' => $parent_hash, \'total_boucle\' => $nb_rows, \'compteur_boucle\' => 0);'; $out .= "\n"; $out .= '$current =& $this->_vars[\''.$hash.'\']; $parent_hash = "'.$hash.'";'; $out .= "\n"; $out .= 'if ($nb_rows > 0): ?>'; if ($preContent) { $out .= $this->parse($preContent, $loopName, self::PRE_CONTENT); } $out .= '_vars[\''.$hash.'\'][\'compteur_boucle\'] += 1; '; $out .= "\n"; $out .= $loopStart; $out .= "\n"; $out .= '$this->_vars[\''.$hash.'\'] = array_merge($this->_vars[\''.$hash.'\'], $row); ?>'; $out .= $this->parseVariables($loopContent); if ($separator) { $out .= '_vars[\''.$hash.'\'][\'compteur_boucle\'] < $nb_rows): ?>'; $out .= $separator; $out .= ''; } $out .= ''; // we put the post-content after the loop content if ($postContent) { $out .= $this->parse($postContent, $loopName, self::POST_CONTENT); } if ($altContent) { $out .= ''; $out .= $this->parse($altContent, $loopName, self::ALT_CONTENT); } $out .= '_vars[\''.$hash.'\'][\'_parent_hash\']; unset($result_'.$hash.', $nb_rows, $this->_vars[\''.$hash.'\']); $this->parent =& $this->_vars[$parent_hash]; ?>'; return $out; } public function display($template) { return $this->fetch($template, false); } public function fetch($template, $no_display = true, $included = false) { $this->currentTemplate = $template; if (!file_exists($this->template_path . $template)) { throw new miniSkelMarkupException('Le fichier à inclure "' . $template . '" n\'existe pas.'); } if (!self::compile_check($template, $this->template_path . $template)) { $content = file_get_contents($this->template_path . $template); $content = strtr($content, array(' '<?php', ' '')); $content = $this->parse($content); $content = 'parent && !isset($parent_hash)) $parent_hash = $this->parent[\'_self_hash\']; '. // For included files 'elseif (!$this->parent) $parent_hash = false; ?>' . $content; self::compile_store($template, $content); } if (!$no_display) { require self::compile_get_path($template); } else { ob_start(); require self::compile_get_path($template); $out = ob_get_contents(); ob_end_clean(); return $out; } return null; } static private function compile_get_path($path) { $hash = sha1($path); return LENCRIER_DATA_ROOT . '/cache/compiled/' . substr($hash, -2) . '/' . $hash; } static private function compile_check($tpl, $check) { if (!file_exists(self::compile_get_path($tpl))) return false; $time = filemtime(self::compile_get_path($tpl)); if (empty($time)) { return false; } if ($time < filemtime($check)) return false; return $time; } static private function compile_store($tpl, $content) { $path = self::compile_get_path($tpl); if (!file_exists(dirname($path))) { mkdir(dirname($path)); } file_put_contents($path, $content); return true; } static public function compile_clear($tpl) { $path = self::compile_get_path($tpl); if (file_exists($path)) unlink($path); return true; } } ?>