| 1 | <?php |
|---|
| 2 | |
|---|
| 3 | require_once(IA_ROOT_DIR . "common/db/textblock.php"); |
|---|
| 4 | require_once(IA_ROOT_DIR . "common/cache.php"); |
|---|
| 5 | require_once(IA_ROOT_DIR . "common/external_libs/simple_html_dom.php"); |
|---|
| 6 | |
|---|
| 7 | // Hijacks title from $text if already there. If $url is null the title |
|---|
| 8 | // will not have a link. |
|---|
| 9 | function hijack_title(&$text, $url, $title) { |
|---|
| 10 | if (preg_match('/^\s*<h1>(.*)<\/h1>(.*)$/sxi', $text, $matches)) { |
|---|
| 11 | $text = $matches[2]; |
|---|
| 12 | if (is_null($url)) { |
|---|
| 13 | return '<h1>'.$matches[1].'</h1>'; |
|---|
| 14 | } else { |
|---|
| 15 | return '<h1>'.format_link($url, $matches[1], false).'</h1>'; |
|---|
| 16 | } |
|---|
| 17 | } else { |
|---|
| 18 | if (is_null($url)) { |
|---|
| 19 | return '<h1>'.html_escape($title).'</h1>'; |
|---|
| 20 | } else { |
|---|
| 21 | return '<h1>'.format_link($url, $title).'</h1>'; |
|---|
| 22 | } |
|---|
| 23 | } |
|---|
| 24 | } |
|---|
| 25 | |
|---|
| 26 | // Returns a snippet of a textblock. The snippet does not contain images |
|---|
| 27 | // (if $remove_images = true) and it doesn't exceed $max_num_words. |
|---|
| 28 | // |
|---|
| 29 | // Some exceptions: |
|---|
| 30 | // * news -- they are fully rendered in the snippet if $whole_news is true |
|---|
| 31 | // * blog posts having a huge first paragraph -- although we exceed the |
|---|
| 32 | // number of words allowed we should have a snippet for this kind of |
|---|
| 33 | // posts after all |
|---|
| 34 | function get_snippet($tb, $max_num_words, $whole_news = false, |
|---|
| 35 | $remove_images = true) { |
|---|
| 36 | $cache_id = 'snip_' . preg_replace('/[^a-z0-9\.\-_]/i', '_', |
|---|
| 37 | $tb['name']) . '_' . $max_num_words . '_' . $whole_news . |
|---|
| 38 | $remove_images . '_' . db_date_parse($tb['timestamp']); |
|---|
| 39 | $cache_res = disk_cache_get($cache_id); |
|---|
| 40 | |
|---|
| 41 | if ($cache_res == false) { |
|---|
| 42 | $url = url_textblock($tb['name']); |
|---|
| 43 | $html_text = wiki_process_textblock_recursive($tb); |
|---|
| 44 | |
|---|
| 45 | $cache_res .= hijack_title($html_text, $url, $tb['title']); |
|---|
| 46 | $cache_res .= '<div class="wiki_text_block">'; |
|---|
| 47 | |
|---|
| 48 | // May be there is a better way to find out if $tb is tagged |
|---|
| 49 | // 'stiri'. On the other hand, this operation is cached and we |
|---|
| 50 | // shouldn't worry too much about performance. |
|---|
| 51 | if ($whole_news && tag_exists('textblock', $tb['name'], tag_get_id( |
|---|
| 52 | array("name" => 'stiri', "type" => "tag", "parent" => 0)))) { |
|---|
| 53 | // Don't compute snippet for news -- they should be rendered as |
|---|
| 54 | // they are in the snippet. |
|---|
| 55 | $cache_res .= $html_text; |
|---|
| 56 | } else { |
|---|
| 57 | $html_dom = str_get_html($html_text); |
|---|
| 58 | $num_words = 0; |
|---|
| 59 | |
|---|
| 60 | if ($remove_images) { |
|---|
| 61 | // Remove all the images -- ussually they look bad in a snippet. |
|---|
| 62 | foreach ($html_dom->find('img') as $element) { |
|---|
| 63 | $element->outertext = ''; |
|---|
| 64 | } |
|---|
| 65 | } |
|---|
| 66 | |
|---|
| 67 | // Select some paragraphs so that the maximum number of words is |
|---|
| 68 | // not exceeded and at least one paragraph is selected. |
|---|
| 69 | foreach ($html_dom->find('p') as $element) { |
|---|
| 70 | $par_words = count(explode(" ", $element->plaintext)); |
|---|
| 71 | if ($num_words + $par_words >= $max_num_words && $num_words > 0) { |
|---|
| 72 | break; |
|---|
| 73 | } |
|---|
| 74 | $num_words += $par_words; |
|---|
| 75 | $cache_res .= $element->outertext(); |
|---|
| 76 | } |
|---|
| 77 | |
|---|
| 78 | $cache_res .= '<a href="' . html_escape($url) . |
|---|
| 79 | '"> » Citeste restul insemnarii</a>'; |
|---|
| 80 | $html_dom->__destruct(); |
|---|
| 81 | unset($html_dom); |
|---|
| 82 | } |
|---|
| 83 | |
|---|
| 84 | $cache_res .= '</div>'; |
|---|
| 85 | disk_cache_set($cache_id, $cache_res, 3); |
|---|
| 86 | } |
|---|
| 87 | |
|---|
| 88 | return $cache_res; |
|---|
| 89 | } |
|---|
| 90 | |
|---|
| 91 | // Check if textblock security string is valid |
|---|
| 92 | // FIXME: check task/round existence? |
|---|
| 93 | function is_textblock_security_descriptor($descriptor) |
|---|
| 94 | { |
|---|
| 95 | return preg_match("/^ \s* task: \s* (".IA_RE_TASK_ID.") \s* $/xi", $descriptor) || |
|---|
| 96 | preg_match("/^ \s* round: \s* (".IA_RE_ROUND_ID.") \s* $/xi", $descriptor) || |
|---|
| 97 | preg_match('/^ \s* (private|protected|public) \s* $/xi', $descriptor); |
|---|
| 98 | } |
|---|
| 99 | |
|---|
| 100 | // Validates a textblock. |
|---|
| 101 | // NOTE: this might be incomplete, so don't rely on it exclusively |
|---|
| 102 | function textblock_validate($tb) { |
|---|
| 103 | $errors = array(); |
|---|
| 104 | |
|---|
| 105 | // FIXME How to handle this? |
|---|
| 106 | log_assert(is_array($tb), "You didn't even pass an array"); |
|---|
| 107 | |
|---|
| 108 | if (!is_normal_page_name(getattr($tb, 'name', ''))) { |
|---|
| 109 | $errors['name'] = 'Nume de pagina invalid.'; |
|---|
| 110 | } |
|---|
| 111 | |
|---|
| 112 | // FIXME: move this in textblock edit controller |
|---|
| 113 | if (strlen(getattr($tb, 'title', '')) < 1) { |
|---|
| 114 | $errors['title'] = 'Titlu prea scurt.'; |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | // FIXME: move this in textblock edit controller |
|---|
| 118 | if (strlen(getattr($tb, 'title', '')) > 64) { |
|---|
| 119 | $errors['title'] = 'Titlu prea lung.'; |
|---|
| 120 | } |
|---|
| 121 | |
|---|
| 122 | if (!is_user_id(getattr($tb, 'user_id'))) { |
|---|
| 123 | $errors['user_id'] = 'ID de utilizator invalid'; |
|---|
| 124 | } |
|---|
| 125 | |
|---|
| 126 | if (!is_null(getattr($tb, 'forum_topic')) && !is_whole_number(getattr($tb, 'forum_topic'))) { |
|---|
| 127 | $errors['forum_topic'] = 'Topic forum invalid'; |
|---|
| 128 | } |
|---|
| 129 | |
|---|
| 130 | // NOTE: missing timestamp is OK!!! |
|---|
| 131 | // It stands for 'current moment'. |
|---|
| 132 | if (!is_db_date(getattr($tb, 'timestamp', db_date_format()))) { |
|---|
| 133 | $errors['timestamp'] = 'Timestamp invalid.'; |
|---|
| 134 | } |
|---|
| 135 | |
|---|
| 136 | if (!is_db_date(getattr($tb, 'creation_timestamp', db_date_format()))) { |
|---|
| 137 | $errors['creation_timestamp'] = 'Timestamp invalid.'; |
|---|
| 138 | } |
|---|
| 139 | |
|---|
| 140 | if (!is_textblock_security_descriptor(getattr($tb, 'security'))) { |
|---|
| 141 | $errors['security'] = "Descriptor de securitate gresit."; |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | return $errors; |
|---|
| 145 | } |
|---|
| 146 | |
|---|
| 147 | // This function copies all starting with $srcprefix and copies the over to |
|---|
| 148 | // $destprefix. |
|---|
| 149 | // It also does template-replacing for everything in $replace, if non-null. |
|---|
| 150 | // You can also change the security descriptor on all those files. |
|---|
| 151 | // |
|---|
| 152 | // Use this like textblock_copy_replace('template/newtask', 'problema/capsuni'); |
|---|
| 153 | function textblock_copy_replace($srcprefix, $dstprefix, $replace, $security, |
|---|
| 154 | $user_id, $remote_ip_info = null) { |
|---|
| 155 | log_assert($srcprefix != $dstprefix); |
|---|
| 156 | log_assert($security === null || |
|---|
| 157 | is_textblock_security_descriptor($security)); |
|---|
| 158 | log_assert(is_whole_number($user_id)); |
|---|
| 159 | |
|---|
| 160 | $textblocks = textblock_get_by_prefix($srcprefix, true, false); |
|---|
| 161 | foreach ($textblocks as $textblock) { |
|---|
| 162 | if ($replace !== null) { |
|---|
| 163 | textblock_template_replace($textblock, $replace); |
|---|
| 164 | } |
|---|
| 165 | if ($security !== null) { |
|---|
| 166 | $textblock['security'] = $security; |
|---|
| 167 | } |
|---|
| 168 | $new_name = preg_replace('/^'.preg_quote($srcprefix, '/').'/i', |
|---|
| 169 | $dstprefix, $textblock['name']); |
|---|
| 170 | |
|---|
| 171 | textblock_copy($textblock, $new_name, $user_id, $remote_ip_info); |
|---|
| 172 | } |
|---|
| 173 | } |
|---|
| 174 | |
|---|
| 175 | // Does template replacing in a textblock. |
|---|
| 176 | // Replaces all occurences of %key% with value, for all key, value pairs |
|---|
| 177 | // in the $replace array. |
|---|
| 178 | // |
|---|
| 179 | // You should mainly use this horrible painful hack on templates. |
|---|
| 180 | // |
|---|
| 181 | // MODIFIES $textblock |
|---|
| 182 | // |
|---|
| 183 | // FIXME: optimize. |
|---|
| 184 | function textblock_template_replace(&$textblock, $replace) |
|---|
| 185 | { |
|---|
| 186 | foreach ($replace as $key => $value) { |
|---|
| 187 | $textblock['title'] = str_replace("%$key%", $value, $textblock['title']); |
|---|
| 188 | $textblock['text'] = str_replace("%$key%", $value, $textblock['text']); |
|---|
| 189 | } |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | // Checks if the textblock is task and returns the task_id if true or false if false |
|---|
| 193 | function textblock_security_is_task($textblock) { |
|---|
| 194 | if (preg_match("/^ \s* task: \s* (".IA_RE_TASK_ID.") \s* $/xi", $textblock, $matches)) { |
|---|
| 195 | return $matches[1]; |
|---|
| 196 | } |
|---|
| 197 | return false; |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | // Checks if the textblock is round and returns the round_id if true or false if false |
|---|
| 201 | function textblock_security_is_round($textblock) { |
|---|
| 202 | if (preg_match("/^ \s* round: \s* (".IA_RE_ROUND_ID.") \s* $/xi", $textblock, $matches)) { |
|---|
| 203 | return $matches[1]; |
|---|
| 204 | } |
|---|
| 205 | return false; |
|---|
| 206 | } |
|---|
| 207 | |
|---|
| 208 | |
|---|
| 209 | ?> |
|---|