File indexing completed on 2025-01-26 05:25:46
0001 <?php 0002 0003 /** 0004 * Flooer Framework 0005 * 0006 * LICENSE: BSD License (2 Clause) 0007 * 0008 * @category Flooer 0009 * @package Flooer_Utility 0010 * @author Akira Ohgaki <akiraohgaki@gmail.com> 0011 * @copyright Akira Ohgaki 0012 * @license https://opensource.org/licenses/BSD-2-Clause BSD License (2 Clause) 0013 * @link https://github.com/akiraohgaki/flooer 0014 */ 0015 0016 /** 0017 * Usage 0018 * 0019 * $xhtmlSource = Flooer_Utility_Element::convert($textSource); 0020 */ 0021 0022 /** 0023 * Element converter class that convert a plain text to a XHTML source 0024 * 0025 * @category Flooer 0026 * @package Flooer_Utility 0027 * @author Akira Ohgaki <akiraohgaki@gmail.com> 0028 */ 0029 class Flooer_Utility_Element 0030 { 0031 0032 /** 0033 * Batch converting 0034 * 0035 * @param string $source 0036 * @return string 0037 */ 0038 public static function convert($source) 0039 { 0040 $source = self::convertNewline($source); 0041 $source = self::convertSpecialchar($source); 0042 $source = self::convertInlineElement($source); 0043 $source = self::convertBlockElement($source); 0044 return $source; 0045 } 0046 0047 /** 0048 * Convert a newline 0049 * 0050 * @param string $source 0051 * @return string 0052 */ 0053 public static function convertNewline($source) 0054 { 0055 // Make a newline into LF 0056 return str_replace(array("\r\n", "\r"), "\n", $source); 0057 } 0058 0059 /** 0060 * Convert a special character 0061 * 0062 * @param string $source 0063 * @return string 0064 */ 0065 public static function convertSpecialchar($source) 0066 { 0067 // Encode a conflicted characters 0068 $encodeConflictChars = function ($matches) { 0069 return rawurlencode(stripslashes($matches[0])); 0070 }; 0071 $source = preg_replace_callback( 0072 "/\"[^\"\n]+\"\<[^\>\n]+\>/", 0073 $encodeConflictChars, 0074 $source 0075 ); 0076 $source = preg_replace_callback( 0077 "/\"[^\"\n]+\"\{[^\}\n]+\}\<[^\>\n]+\>/", 0078 $encodeConflictChars, 0079 $source 0080 ); 0081 $source = preg_replace_callback( 0082 "/\"[^\"\n]+\"\{[^\}\n]+\}/", 0083 $encodeConflictChars, 0084 $source 0085 ); 0086 $source = preg_replace_callback( 0087 "/\"[^\"\n]+\"\([^\)\n]+\)/", 0088 $encodeConflictChars, 0089 $source 0090 ); 0091 $source = str_replace("\n>", "\n" . rawurlencode('>'), $source); 0092 // Make a characters into a character-entity 0093 $source = str_replace("\t", ' ', $source); // tab to 4 spaces 0094 $source = str_replace('&', '&', $source); 0095 $source = str_replace('"', '"', $source); 0096 $source = str_replace("'", ''', $source); 0097 $source = str_replace('<', '<', $source); 0098 $source = str_replace('>', '>', $source); 0099 $source = str_ireplace('(C)', '©', $source); 0100 $source = str_ireplace('(R)', '®', $source); 0101 $source = str_ireplace('(TM)', '™', $source); 0102 // Decode a conflicted characters 0103 $source = rawurldecode($source); 0104 return $source; 0105 } 0106 0107 /** 0108 * Convert an inline element 0109 * 0110 * @param string $source 0111 * @return string 0112 */ 0113 public static function convertInlineElement($source) 0114 { 0115 // Anchor 0116 // "title"<uri> 0117 $source = preg_replace( 0118 "/\"([^\"\n]+)\"\<([^\>\n]+)\>/", 0119 "<a href=\"$2\" title=\"$1\">$1</a>", 0120 $source 0121 ); 0122 // Image Anchor 0123 // "title"{image-uri}<uri> 0124 $source = preg_replace( 0125 "/\"([^\"\n]+)\"\{([^\}\n]+)\}\<([^\>\n]+)\>/", 0126 "<a href=\"$3\" title=\"$1\"><img src=\"$2\" alt=\"$1\" /></a>", 0127 $source 0128 ); 0129 // Image 0130 // "title"{image-uri} 0131 $source = preg_replace( 0132 "/\"([^\"\n]+)\"\{([^\}\n]+)\}/", 0133 "<img src=\"$2\" alt=\"$1\" />", 0134 $source 0135 ); 0136 // Abbreviation 0137 // "abbr"(Abbreviation) 0138 $source = preg_replace( 0139 "/\"([^\"\n]+)\"\(([^\)\n]+)\)/", 0140 "<abbr title=\"$2\">$1</abbr>", 0141 $source 0142 ); 0143 // Strong Emphasis 0144 // ***strong*** 0145 $source = preg_replace( 0146 "/\*\*\*([^\*\n]+)\*\*\*/", 0147 "<strong>$1</strong>", 0148 $source 0149 ); 0150 // Emphasis 0151 // **em** 0152 $source = preg_replace( 0153 "/\*\*([^\*\n]+)\*\*/", 0154 "<em>$1</em>", 0155 $source 0156 ); 0157 // Subscript 0158 // ~~sub~~ 0159 $source = preg_replace( 0160 "/\~\~([^\~\n]+)\~\~/", 0161 "<sub>$1</sub>", 0162 $source 0163 ); 0164 // Superscript 0165 // ^^sup^^ 0166 $source = preg_replace( 0167 "/\^\^([^\^\n]+)\^\^/", 0168 "<sup>$1</sup>", 0169 $source 0170 ); 0171 // Insert 0172 // ++ins++ 0173 $source = preg_replace( 0174 "/\+\+([^\+\n]+)\+\+/", 0175 "<ins>$1</ins>", 0176 $source 0177 ); 0178 // Delete 0179 // --del-- 0180 $source = preg_replace( 0181 "/\-\-([^\-\n]+)\-\-/", 0182 "<del>$1</del>", 0183 $source 0184 ); 0185 return $source; 0186 } 0187 0188 /** 0189 * Convert a block element 0190 * 0191 * @param string $source 0192 * @return string 0193 */ 0194 public static function convertBlockElement($source) 0195 { 0196 $sourceLines = explode("\n", $source); 0197 $totalSourceLines = count($sourceLines); 0198 $isBlockContinueable = false; 0199 $isLineBreakable = false; 0200 for ($i = 0; $i < $totalSourceLines; $i++) { 0201 $sourceLines[$i] = rtrim($sourceLines[$i]); 0202 $n = $i + 1; 0203 if (!isset($sourceLines[$n])) { 0204 $sourceLines[$n] = ''; 0205 } 0206 // Blank line 0207 // Blank line is removes. 0208 if ($sourceLines[$i] == '') { 0209 unset($sourceLines[$i]); 0210 continue; 0211 } 0212 // Commentation 0213 // // Comment line 1 0214 // // Comment line 2 0215 // // Comment line 3 0216 // Comment line is removes. 0217 else if (preg_match("/^\/\//", $sourceLines[$i])) { 0218 unset($sourceLines[$i]); 0219 continue; 0220 } 0221 // Division 0222 // ****** 0223 // ++++++ 0224 // ------ 0225 // "*/+/-" is 4 characters or more required. 0226 else if (preg_match("/^(\*|\+|\-){4,}$/", $sourceLines[$i])) { 0227 $sourceLines[$i] = "</div>\n<div>"; 0228 $isBlockContinueable = false; 0229 $isLineBreakable = false; 0230 } 0231 // Heading 0232 // = Heading 1 = 0233 // ====== Heading 6 ====== 0234 // # Heading 1 # 0235 // ###### Heading 6 ###### 0236 // Closing "=/#" is an option and not counted. 0237 else if (preg_match("/(^[\=\#]{1,6})[ \t]*(.*)/", $sourceLines[$i], $matches)) { 0238 $matches[1] = strlen($matches[1]); 0239 $matches[2] = preg_replace("/[ \t\=\#]*$/", '', $matches[2]); 0240 $sourceLines[$i] = "<h{$matches[1]}>{$matches[2]}</h{$matches[1]}>"; 0241 $isBlockContinueable = false; 0242 $isLineBreakable = false; 0243 } 0244 // Address 0245 // @ Address line 1 0246 // @ Address line 2 0247 // @ Address line 3 0248 else if (preg_match("/^\@[ \t]*(.*)/", $sourceLines[$i], $matches)) { 0249 $sourceLines[$i] = $matches[1]; 0250 if (!$isBlockContinueable) { 0251 $sourceLines[$i] = "<address>\n{$sourceLines[$i]}"; 0252 $isBlockContinueable = true; 0253 $isLineBreakable = true; 0254 } 0255 if (!preg_match("/^\@/", $sourceLines[$n])) { 0256 $sourceLines[$i] .= "\n</address>"; 0257 $isBlockContinueable = false; 0258 $isLineBreakable = false; 0259 } 0260 } 0261 // Preformatted Text 0262 // \sPreformatted Text line 1 0263 // \tPreformatted Text line 2 0264 // \s\tPreformatted Text line 3 0265 // "\s" is a space and "\t" is a tab. 0266 else if (preg_match("/^[ \t].*/", $sourceLines[$i])) { 0267 if (!$isBlockContinueable) { 0268 $sourceLines[$i] = "<pre>\n{$sourceLines[$i]}"; 0269 $isBlockContinueable = true; 0270 $isLineBreakable = false; 0271 } 0272 if (!preg_match("/^[ \t]/", $sourceLines[$n])) { 0273 $sourceLines[$i] .= "\n</pre>"; 0274 $isBlockContinueable = false; 0275 $isLineBreakable = false; 0276 } 0277 } 0278 // Block Quote 0279 // > Block Quote line 1 0280 // > Block Quote line 2 0281 // > Block Quote line 3 0282 else if (preg_match("/^\>[ \t]*(.*)/", $sourceLines[$i], $matches)) { 0283 $sourceLines[$i] = $matches[1]; 0284 if (!$isBlockContinueable) { 0285 $sourceLines[$i] = "<blockquote>\n{$sourceLines[$i]}"; 0286 $isBlockContinueable = true; 0287 $isLineBreakable = true; 0288 } 0289 if (!preg_match("/^\>/", $sourceLines[$n])) { 0290 $sourceLines[$i] .= "\n</blockquote>"; 0291 $isBlockContinueable = false; 0292 $isLineBreakable = false; 0293 } 0294 } 0295 // Ordered List 0296 // 1. Ordered List 1 0297 // 2. Ordered List 2 0298 // 3. Ordered List 3 0299 else if (preg_match("/(^[1-9][0-9]*)\.[ \t]*(.*)/", $sourceLines[$i], $matches)) { 0300 $sourceLines[$i] = "<li>{$matches[2]}</li>"; 0301 if (!$isBlockContinueable) { 0302 $sourceLines[$i] = "<ol start=\"{$matches[1]}\">\n{$sourceLines[$i]}"; 0303 $isBlockContinueable = true; 0304 $isLineBreakable = false; 0305 } 0306 if (!preg_match("/^[1-9][0-9]*\./", $sourceLines[$n])) { 0307 $sourceLines[$i] .= "\n</ol>"; 0308 $isBlockContinueable = false; 0309 $isLineBreakable = false; 0310 } 0311 } 0312 // Unordered List 0313 // * Unordered List 1 0314 // + Unordered List 2 0315 // - Unordered List 3 0316 else if (preg_match("/^[\*\+\-][ \t]*(.*)/", $sourceLines[$i], $matches)) { 0317 $sourceLines[$i] = "<li>{$matches[1]}</li>"; 0318 if (!$isBlockContinueable) { 0319 $sourceLines[$i] = "<ul>\n{$sourceLines[$i]}"; 0320 $isBlockContinueable = true; 0321 $isLineBreakable = false; 0322 } 0323 if (!preg_match("/^[\*\+\-]+[^\*\+\-]+/", $sourceLines[$n])) { 0324 $sourceLines[$i] .= "\n</ul>"; 0325 $isBlockContinueable = false; 0326 $isLineBreakable = false; 0327 } 0328 } 0329 // Definition List 0330 // | dl1 | Definition List 1 0331 // | dl2 | Definition List 2 0332 // | dl3 | Definition List 3 0333 else if (preg_match("/^\|[ \t]*(.*)\|[ \t]*(.*)/", $sourceLines[$i], $matches)) { 0334 $matches[1] = rtrim($matches[1]); 0335 $sourceLines[$i] = "<dt>{$matches[1]}</dt>\n<dd>{$matches[2]}</dd>"; 0336 if (!$isBlockContinueable) { 0337 $sourceLines[$i] = "<dl>\n{$sourceLines[$i]}"; 0338 $isBlockContinueable = true; 0339 $isLineBreakable = false; 0340 } 0341 if (!preg_match("/^\|.*\|/", $sourceLines[$n])) { 0342 $sourceLines[$i] .= "\n</dl>"; 0343 $isBlockContinueable = false; 0344 $isLineBreakable = false; 0345 } 0346 } 0347 // Paragraph 0348 // A line without markup is a paragraph and separate as a blank line. 0349 else { 0350 if (!$isBlockContinueable) { 0351 $sourceLines[$i] = "<p>\n{$sourceLines[$i]}"; 0352 $isBlockContinueable = true; 0353 $isLineBreakable = true; 0354 } 0355 if ($sourceLines[$n] == '' 0356 || preg_match("/^([ \t\=\#\>\@\*\+\-]|[1-9][0-9]*\.|\|.*\|)/", $sourceLines[$n]) 0357 ) { 0358 $sourceLines[$i] .= "\n</p>"; 0359 $isBlockContinueable = false; 0360 $isLineBreakable = false; 0361 } 0362 } 0363 // Line break 0364 if ($isLineBreakable) { 0365 $sourceLines[$i] .= '<br />'; 0366 } 0367 } 0368 // Enclosed with a div tag 0369 $source = "<div>\n" . implode("\n", $sourceLines) . "\n</div>"; 0370 return $source; 0371 } 0372 0373 }