Changeset 2149939
- Timestamp:
- 09/03/2019 05:51:01 AM (7 years ago)
- Location:
- hosted-content-importer/trunk
- Files:
-
- 1 added
- 5 edited
-
classes/hci/class.hosted_content_importer.inc.php (modified) (1 diff)
-
classes/parsedown/LICENSE.txt (modified) (1 diff)
-
classes/parsedown/Parsedown.php (modified) (64 diffs)
-
classes/processors/class.processor_code.inc.php (added)
-
hosted-content-importer.php (modified) (4 diffs)
-
readme.txt (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
hosted-content-importer/trunk/classes/hci/class.hosted_content_importer.inc.php
r1434331 r2149939 115 115 private function _autoload_processors($class_name = '') 116 116 { 117 $processor = require_once(HCI_PLUGIN_DIR . "/classes/processors/class.{$class_name}.inc.php"); 118 if(is_file($processor)) 119 { 120 require_once($processor); 121 } 117 if(file_exists(HCI_PLUGIN_DIR . "/classes/processors/class.{$class_name}.inc.php")) 118 { 119 $processor = require_once(HCI_PLUGIN_DIR . "/classes/processors/class.{$class_name}.inc.php"); 120 if(is_file($processor)) 121 { 122 require_once($processor); 123 } 124 } 122 125 } 123 126 } -
hosted-content-importer/trunk/classes/parsedown/LICENSE.txt
r1397630 r2149939 1 1 The MIT License (MIT) 2 2 3 Copyright (c) 2013 Emanuil Rusev, erusev.com3 Copyright (c) 2013-2018 Emanuil Rusev, erusev.com 4 4 5 5 Permission is hereby granted, free of charge, to any person obtaining a copy of -
hosted-content-importer/trunk/classes/parsedown/Parsedown.php
r1412458 r2149939 18 18 # ~ 19 19 20 const version = '1. 6.0';20 const version = '1.8.0-beta-7'; 21 21 22 22 # ~ 23 23 24 24 function text($text) 25 { 26 $Elements = $this->textElements($text); 27 28 # convert to markup 29 $markup = $this->elements($Elements); 30 31 # trim line breaks 32 $markup = trim($markup, "\n"); 33 34 return $markup; 35 } 36 37 protected function textElements($text) 25 38 { 26 39 # make sure no definitions are set … … 37 50 38 51 # iterate through lines to identify blocks 39 $markup = $this->lines($lines); 40 41 # trim line breaks 42 $markup = trim($markup, "\n"); 43 44 return $markup; 52 return $this->linesElements($lines); 45 53 } 46 54 … … 75 83 76 84 protected $urlsLinked = true; 85 86 function setSafeMode($safeMode) 87 { 88 $this->safeMode = (bool) $safeMode; 89 90 return $this; 91 } 92 93 protected $safeMode; 94 95 function setStrictMode($strictMode) 96 { 97 $this->strictMode = (bool) $strictMode; 98 99 return $this; 100 } 101 102 protected $strictMode; 103 104 protected $safeLinksWhitelist = array( 105 'http://', 106 'https://', 107 'ftp://', 108 'ftps://', 109 'mailto:', 110 'tel:', 111 'data:image/png;base64,', 112 'data:image/gif;base64,', 113 'data:image/jpeg;base64,', 114 'irc:', 115 'ircs:', 116 'git:', 117 'ssh:', 118 'news:', 119 'steam:', 120 ); 77 121 78 122 # … … 118 162 protected function lines(array $lines) 119 163 { 164 return $this->elements($this->linesElements($lines)); 165 } 166 167 protected function linesElements(array $lines) 168 { 169 $Elements = array(); 120 170 $CurrentBlock = null; 121 171 … … 126 176 if (isset($CurrentBlock)) 127 177 { 128 $CurrentBlock['interrupted'] = true; 178 $CurrentBlock['interrupted'] = (isset($CurrentBlock['interrupted']) 179 ? $CurrentBlock['interrupted'] + 1 : 1 180 ); 129 181 } 130 182 … … 132 184 } 133 185 134 if (strpos($line, "\t") !== false) 135 { 136 $parts = explode("\t", $line); 137 138 $line = $parts[0]; 139 140 unset($parts[0]); 141 142 foreach ($parts as $part) 143 { 144 $shortage = 4 - mb_strlen($line, 'utf-8') % 4; 145 146 $line .= str_repeat(' ', $shortage); 147 $line .= $part; 148 } 149 } 150 151 $indent = 0; 152 153 while (isset($line[$indent]) and $line[$indent] === ' ') 154 { 155 $indent ++; 156 } 186 while (($beforeTab = strstr($line, "\t", true)) !== false) 187 { 188 $shortage = 4 - mb_strlen($beforeTab, 'utf-8') % 4; 189 190 $line = $beforeTab 191 . str_repeat(' ', $shortage) 192 . substr($line, strlen($beforeTab) + 1) 193 ; 194 } 195 196 $indent = strspn($line, ' '); 157 197 158 198 $text = $indent > 0 ? substr($line, $indent) : $line; … … 166 206 if (isset($CurrentBlock['continuable'])) 167 207 { 168 $Block = $this->{'block'.$CurrentBlock['type'].'Continue'}($Line, $CurrentBlock); 208 $methodName = 'block' . $CurrentBlock['type'] . 'Continue'; 209 $Block = $this->$methodName($Line, $CurrentBlock); 169 210 170 211 if (isset($Block)) … … 178 219 if ($this->isBlockCompletable($CurrentBlock['type'])) 179 220 { 180 $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); 221 $methodName = 'block' . $CurrentBlock['type'] . 'Complete'; 222 $CurrentBlock = $this->$methodName($CurrentBlock); 181 223 } 182 224 } … … 204 246 foreach ($blockTypes as $blockType) 205 247 { 206 $Block = $this->{ 'block'.$blockType}($Line, $CurrentBlock);248 $Block = $this->{"block$blockType"}($Line, $CurrentBlock); 207 249 208 250 if (isset($Block)) … … 212 254 if ( ! isset($Block['identified'])) 213 255 { 214 $Blocks []= $CurrentBlock; 256 if (isset($CurrentBlock)) 257 { 258 $Elements[] = $this->extractElement($CurrentBlock); 259 } 215 260 216 261 $Block['identified'] = true; … … 230 275 # ~ 231 276 232 if (isset($CurrentBlock) and ! isset($CurrentBlock['type']) and ! isset($CurrentBlock['interrupted'])) 233 { 234 $CurrentBlock['element']['text'] .= "\n".$text; 277 if (isset($CurrentBlock) and $CurrentBlock['type'] === 'Paragraph') 278 { 279 $Block = $this->paragraphContinue($Line, $CurrentBlock); 280 } 281 282 if (isset($Block)) 283 { 284 $CurrentBlock = $Block; 235 285 } 236 286 else 237 287 { 238 $Blocks []= $CurrentBlock; 288 if (isset($CurrentBlock)) 289 { 290 $Elements[] = $this->extractElement($CurrentBlock); 291 } 239 292 240 293 $CurrentBlock = $this->paragraph($Line); … … 248 301 if (isset($CurrentBlock['continuable']) and $this->isBlockCompletable($CurrentBlock['type'])) 249 302 { 250 $CurrentBlock = $this->{'block'.$CurrentBlock['type'].'Complete'}($CurrentBlock); 303 $methodName = 'block' . $CurrentBlock['type'] . 'Complete'; 304 $CurrentBlock = $this->$methodName($CurrentBlock); 251 305 } 252 306 253 307 # ~ 254 308 255 $Blocks []= $CurrentBlock; 256 257 unset($Blocks[0]); 309 if (isset($CurrentBlock)) 310 { 311 $Elements[] = $this->extractElement($CurrentBlock); 312 } 258 313 259 314 # ~ 260 315 261 $markup = '';262 263 foreach ($Blocks as $Block) 264 {265 if (isset($Block['hidden']))266 {267 continue;268 }269 270 $markup .= "\n";271 $markup .= isset($Block['markup']) ? $Block['markup'] : $this->element($Block['element']);272 }273 274 $markup .= "\n";275 276 # ~277 278 return $ markup;316 return $Elements; 317 } 318 319 protected function extractElement(array $Component) 320 { 321 if ( ! isset($Component['element'])) 322 { 323 if (isset($Component['markup'])) 324 { 325 $Component['element'] = array('rawHtml' => $Component['markup']); 326 } 327 elseif (isset($Component['hidden'])) 328 { 329 $Component['element'] = array(); 330 } 331 } 332 333 return $Component['element']; 279 334 } 280 335 281 336 protected function isBlockContinuable($Type) 282 337 { 283 return method_exists($this, 'block' .$Type.'Continue');338 return method_exists($this, 'block' . $Type . 'Continue'); 284 339 } 285 340 286 341 protected function isBlockCompletable($Type) 287 342 { 288 return method_exists($this, 'block' .$Type.'Complete');343 return method_exists($this, 'block' . $Type . 'Complete'); 289 344 } 290 345 … … 294 349 protected function blockCode($Line, $Block = null) 295 350 { 296 if (isset($Block) and ! isset($Block['type'])and ! isset($Block['interrupted']))351 if (isset($Block) and $Block['type'] === 'Paragraph' and ! isset($Block['interrupted'])) 297 352 { 298 353 return; … … 306 361 'element' => array( 307 362 'name' => 'pre', 308 'handler' => 'element', 309 'text' => array( 363 'element' => array( 310 364 'name' => 'code', 311 365 'text' => $text, … … 324 378 if (isset($Block['interrupted'])) 325 379 { 326 $Block['element'][' text']['text'] .= "\n";380 $Block['element']['element']['text'] .= str_repeat("\n", $Block['interrupted']); 327 381 328 382 unset($Block['interrupted']); 329 383 } 330 384 331 $Block['element'][' text']['text'] .= "\n";385 $Block['element']['element']['text'] .= "\n"; 332 386 333 387 $text = substr($Line['body'], 4); 334 388 335 $Block['element'][' text']['text'] .= $text;389 $Block['element']['element']['text'] .= $text; 336 390 337 391 return $Block; … … 341 395 protected function blockCodeComplete($Block) 342 396 { 343 $text = $Block['element']['text']['text'];344 345 $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8');346 347 $Block['element']['text']['text'] = $text;348 349 397 return $Block; 350 398 } … … 355 403 protected function blockComment($Line) 356 404 { 357 if ($this->markupEscaped) 358 { 359 return; 360 } 361 362 if (isset($Line['text'][3]) and $Line['text'][3] === '-' and $Line['text'][2] === '-' and $Line['text'][1] === '!') 363 { 364 $Block = array( 365 'markup' => $Line['body'], 366 ); 367 368 if (preg_match('/-->$/', $Line['text'])) 369 { 370 $Block['closed'] = true; 371 } 372 373 return $Block; 374 } 375 } 376 377 protected function blockCommentContinue($Line, array $Block) 378 { 379 if (isset($Block['closed'])) 380 { 381 return; 382 } 383 384 $Block['markup'] .= "\n" . $Line['body']; 385 386 if (preg_match('/-->$/', $Line['text'])) 387 { 388 $Block['closed'] = true; 389 } 390 391 return $Block; 392 } 393 394 # 395 # Fenced Code 396 397 protected function blockFencedCode($Line) 398 { 399 if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([\w-]+)?[ ]*$/', $Line['text'], $matches)) 400 { 401 $Element = array( 402 'name' => 'code', 403 'text' => '', 404 ); 405 406 if (isset($matches[1])) 407 { 408 $class = 'language-'.$matches[1]; 409 410 $Element['attributes'] = array( 411 'class' => $class, 412 ); 413 } 414 415 $Block = array( 416 'char' => $Line['text'][0], 417 'element' => array( 418 'name' => 'pre', 419 'handler' => 'element', 420 'text' => $Element, 421 ), 422 ); 423 424 return $Block; 425 } 426 } 427 428 protected function blockFencedCodeContinue($Line, $Block) 429 { 430 if (isset($Block['complete'])) 431 { 432 return; 433 } 434 435 if (isset($Block['interrupted'])) 436 { 437 $Block['element']['text']['text'] .= "\n"; 438 439 unset($Block['interrupted']); 440 } 441 442 if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text'])) 443 { 444 $Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1); 445 446 $Block['complete'] = true; 447 448 return $Block; 449 } 450 451 $Block['element']['text']['text'] .= "\n".$Line['body'];; 452 453 return $Block; 454 } 455 456 protected function blockFencedCodeComplete($Block) 457 { 458 $text = $Block['element']['text']['text']; 459 460 $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); 461 462 $Block['element']['text']['text'] = $text; 463 464 return $Block; 465 } 466 467 # 468 # Header 469 470 protected function blockHeader($Line) 471 { 472 if (isset($Line['text'][1])) 473 { 474 $level = 1; 475 476 while (isset($Line['text'][$level]) and $Line['text'][$level] === '#') 477 { 478 $level ++; 479 } 480 481 if ($level > 6) 482 { 483 return; 484 } 485 486 $text = trim($Line['text'], '# '); 487 405 if ($this->markupEscaped or $this->safeMode) 406 { 407 return; 408 } 409 410 if (strpos($Line['text'], '<!--') === 0) 411 { 488 412 $Block = array( 489 413 'element' => array( 490 'name' => 'h' . min(6, $level), 491 'text' => $text, 492 'handler' => 'line', 414 'rawHtml' => $Line['body'], 415 'autobreak' => true, 493 416 ), 494 417 ); 495 418 419 if (strpos($Line['text'], '-->') !== false) 420 { 421 $Block['closed'] = true; 422 } 423 496 424 return $Block; 497 425 } 498 426 } 499 427 428 protected function blockCommentContinue($Line, array $Block) 429 { 430 if (isset($Block['closed'])) 431 { 432 return; 433 } 434 435 $Block['element']['rawHtml'] .= "\n" . $Line['body']; 436 437 if (strpos($Line['text'], '-->') !== false) 438 { 439 $Block['closed'] = true; 440 } 441 442 return $Block; 443 } 444 445 # 446 # Fenced Code 447 448 protected function blockFencedCode($Line) 449 { 450 $marker = $Line['text'][0]; 451 452 $openerLength = strspn($Line['text'], $marker); 453 454 if ($openerLength < 3) 455 { 456 return; 457 } 458 459 $infostring = trim(substr($Line['text'], $openerLength), "\t "); 460 461 if (strpos($infostring, '`') !== false) 462 { 463 return; 464 } 465 466 $Element = array( 467 'name' => 'code', 468 'text' => '', 469 ); 470 471 if ($infostring !== '') 472 { 473 /** 474 * https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes 475 * Every HTML element may have a class attribute specified. 476 * The attribute, if specified, must have a value that is a set 477 * of space-separated tokens representing the various classes 478 * that the element belongs to. 479 * [...] 480 * The space characters, for the purposes of this specification, 481 * are U+0020 SPACE, U+0009 CHARACTER TABULATION (tab), 482 * U+000A LINE FEED (LF), U+000C FORM FEED (FF), and 483 * U+000D CARRIAGE RETURN (CR). 484 */ 485 $language = substr($infostring, 0, strcspn($infostring, " \t\n\f\r")); 486 487 $Element['attributes'] = array('class' => "language-$language"); 488 } 489 490 $Block = array( 491 'char' => $marker, 492 'openerLength' => $openerLength, 493 'element' => array( 494 'name' => 'pre', 495 'element' => $Element, 496 ), 497 ); 498 499 return $Block; 500 } 501 502 protected function blockFencedCodeContinue($Line, $Block) 503 { 504 if (isset($Block['complete'])) 505 { 506 return; 507 } 508 509 if (isset($Block['interrupted'])) 510 { 511 $Block['element']['element']['text'] .= str_repeat("\n", $Block['interrupted']); 512 513 unset($Block['interrupted']); 514 } 515 516 if (($len = strspn($Line['text'], $Block['char'])) >= $Block['openerLength'] 517 and chop(substr($Line['text'], $len), ' ') === '' 518 ) { 519 $Block['element']['element']['text'] = substr($Block['element']['element']['text'], 1); 520 521 $Block['complete'] = true; 522 523 return $Block; 524 } 525 526 $Block['element']['element']['text'] .= "\n" . $Line['body']; 527 528 return $Block; 529 } 530 531 protected function blockFencedCodeComplete($Block) 532 { 533 return $Block; 534 } 535 536 # 537 # Header 538 539 protected function blockHeader($Line) 540 { 541 $level = strspn($Line['text'], '#'); 542 543 if ($level > 6) 544 { 545 return; 546 } 547 548 $text = trim($Line['text'], '#'); 549 550 if ($this->strictMode and isset($text[0]) and $text[0] !== ' ') 551 { 552 return; 553 } 554 555 $text = trim($text, ' '); 556 557 $Block = array( 558 'element' => array( 559 'name' => 'h' . $level, 560 'handler' => array( 561 'function' => 'lineElements', 562 'argument' => $text, 563 'destination' => 'elements', 564 ) 565 ), 566 ); 567 568 return $Block; 569 } 570 500 571 # 501 572 # List 502 573 503 protected function blockList($Line) 504 { 505 list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]+[.]'); 506 507 if (preg_match('/^('.$pattern.'[ ]+)(.*)/', $Line['text'], $matches)) 508 { 574 protected function blockList($Line, array $CurrentBlock = null) 575 { 576 list($name, $pattern) = $Line['text'][0] <= '-' ? array('ul', '[*+-]') : array('ol', '[0-9]{1,9}+[.\)]'); 577 578 if (preg_match('/^('.$pattern.'([ ]++|$))(.*+)/', $Line['text'], $matches)) 579 { 580 $contentIndent = strlen($matches[2]); 581 582 if ($contentIndent >= 5) 583 { 584 $contentIndent -= 1; 585 $matches[1] = substr($matches[1], 0, -$contentIndent); 586 $matches[3] = str_repeat(' ', $contentIndent) . $matches[3]; 587 } 588 elseif ($contentIndent === 0) 589 { 590 $matches[1] .= ' '; 591 } 592 593 $markerWithoutWhitespace = strstr($matches[1], ' ', true); 594 509 595 $Block = array( 510 596 'indent' => $Line['indent'], 511 597 'pattern' => $pattern, 598 'data' => array( 599 'type' => $name, 600 'marker' => $matches[1], 601 'markerType' => ($name === 'ul' ? $markerWithoutWhitespace : substr($markerWithoutWhitespace, -1)), 602 ), 512 603 'element' => array( 513 604 'name' => $name, 514 ' handler' => 'elements',605 'elements' => array(), 515 606 ), 516 607 ); 608 $Block['data']['markerTypeRegex'] = preg_quote($Block['data']['markerType'], '/'); 609 610 if ($name === 'ol') 611 { 612 $listStart = ltrim(strstr($matches[1], $Block['data']['markerType'], true), '0') ?: '0'; 613 614 if ($listStart !== '1') 615 { 616 if ( 617 isset($CurrentBlock) 618 and $CurrentBlock['type'] === 'Paragraph' 619 and ! isset($CurrentBlock['interrupted']) 620 ) { 621 return; 622 } 623 624 $Block['element']['attributes'] = array('start' => $listStart); 625 } 626 } 517 627 518 628 $Block['li'] = array( 519 629 'name' => 'li', 520 'handler' => 'li', 521 'text' => array( 522 $matches[2], 523 ), 524 ); 525 526 $Block['element']['text'] []= & $Block['li']; 630 'handler' => array( 631 'function' => 'li', 632 'argument' => !empty($matches[3]) ? array($matches[3]) : array(), 633 'destination' => 'elements' 634 ) 635 ); 636 637 $Block['element']['elements'] []= & $Block['li']; 527 638 528 639 return $Block; … … 532 643 protected function blockListContinue($Line, array $Block) 533 644 { 534 if ($Block['indent'] === $Line['indent'] and preg_match('/^'.$Block['pattern'].'(?:[ ]+(.*)|$)/', $Line['text'], $matches)) 535 { 645 if (isset($Block['interrupted']) and empty($Block['li']['handler']['argument'])) 646 { 647 return null; 648 } 649 650 $requiredIndent = ($Block['indent'] + strlen($Block['data']['marker'])); 651 652 if ($Line['indent'] < $requiredIndent 653 and ( 654 ( 655 $Block['data']['type'] === 'ol' 656 and preg_match('/^[0-9]++'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches) 657 ) or ( 658 $Block['data']['type'] === 'ul' 659 and preg_match('/^'.$Block['data']['markerTypeRegex'].'(?:[ ]++(.*)|$)/', $Line['text'], $matches) 660 ) 661 ) 662 ) { 536 663 if (isset($Block['interrupted'])) 537 664 { 538 $Block['li']['text'] []= ''; 665 $Block['li']['handler']['argument'] []= ''; 666 667 $Block['loose'] = true; 539 668 540 669 unset($Block['interrupted']); … … 544 673 545 674 $text = isset($matches[1]) ? $matches[1] : ''; 675 676 $Block['indent'] = $Line['indent']; 546 677 547 678 $Block['li'] = array( 548 679 'name' => 'li', 549 'handler' => 'li', 550 'text' => array( 551 $text, 552 ), 553 ); 554 555 $Block['element']['text'] []= & $Block['li']; 680 'handler' => array( 681 'function' => 'li', 682 'argument' => array($text), 683 'destination' => 'elements' 684 ) 685 ); 686 687 $Block['element']['elements'] []= & $Block['li']; 556 688 557 689 return $Block; 558 690 } 691 elseif ($Line['indent'] < $requiredIndent and $this->blockList($Line)) 692 { 693 return null; 694 } 559 695 560 696 if ($Line['text'][0] === '[' and $this->blockReference($Line)) … … 563 699 } 564 700 701 if ($Line['indent'] >= $requiredIndent) 702 { 703 if (isset($Block['interrupted'])) 704 { 705 $Block['li']['handler']['argument'] []= ''; 706 707 $Block['loose'] = true; 708 709 unset($Block['interrupted']); 710 } 711 712 $text = substr($Line['body'], $requiredIndent); 713 714 $Block['li']['handler']['argument'] []= $text; 715 716 return $Block; 717 } 718 565 719 if ( ! isset($Block['interrupted'])) 566 720 { 567 $text = preg_replace('/^[ ]{0, 4}/', '', $Line['body']);568 569 $Block['li'][' text'] []= $text;721 $text = preg_replace('/^[ ]{0,'.$requiredIndent.'}+/', '', $Line['body']); 722 723 $Block['li']['handler']['argument'] []= $text; 570 724 571 725 return $Block; 572 726 } 573 574 if ($Line['indent'] > 0) 575 { 576 $Block['li']['text'] []= ''; 577 578 $text = preg_replace('/^[ ]{0,4}/', '', $Line['body']); 579 580 $Block['li']['text'] []= $text; 581 582 unset($Block['interrupted']); 583 584 return $Block; 585 } 727 } 728 729 protected function blockListComplete(array $Block) 730 { 731 if (isset($Block['loose'])) 732 { 733 foreach ($Block['element']['elements'] as &$li) 734 { 735 if (end($li['handler']['argument']) !== '') 736 { 737 $li['handler']['argument'] []= ''; 738 } 739 } 740 } 741 742 return $Block; 586 743 } 587 744 … … 591 748 protected function blockQuote($Line) 592 749 { 593 if (preg_match('/^>[ ]? (.*)/', $Line['text'], $matches))750 if (preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches)) 594 751 { 595 752 $Block = array( 596 753 'element' => array( 597 754 'name' => 'blockquote', 598 'handler' => 'lines', 599 'text' => (array) $matches[1], 755 'handler' => array( 756 'function' => 'linesElements', 757 'argument' => (array) $matches[1], 758 'destination' => 'elements', 759 ) 600 760 ), 601 761 ); … … 607 767 protected function blockQuoteContinue($Line, array $Block) 608 768 { 609 if ($Line['text'][0] === '>' and preg_match('/^>[ ]?(.*)/', $Line['text'], $matches)) 610 { 611 if (isset($Block['interrupted'])) 612 { 613 $Block['element']['text'] []= ''; 614 615 unset($Block['interrupted']); 616 } 617 618 $Block['element']['text'] []= $matches[1]; 769 if (isset($Block['interrupted'])) 770 { 771 return; 772 } 773 774 if ($Line['text'][0] === '>' and preg_match('/^>[ ]?+(.*+)/', $Line['text'], $matches)) 775 { 776 $Block['element']['handler']['argument'] []= $matches[1]; 619 777 620 778 return $Block; … … 623 781 if ( ! isset($Block['interrupted'])) 624 782 { 625 $Block['element'][' text'] []= $Line['text'];783 $Block['element']['handler']['argument'] []= $Line['text']; 626 784 627 785 return $Block; … … 634 792 protected function blockRule($Line) 635 793 { 636 if (preg_match('/^(['.$Line['text'][0].'])([ ]*\1){2,}[ ]*$/', $Line['text'])) 794 $marker = $Line['text'][0]; 795 796 if (substr_count($Line['text'], $marker) >= 3 and chop($Line['text'], " $marker") === '') 637 797 { 638 798 $Block = array( 639 799 'element' => array( 640 'name' => 'hr' 800 'name' => 'hr', 641 801 ), 642 802 ); … … 651 811 protected function blockSetextHeader($Line, array $Block = null) 652 812 { 653 if ( ! isset($Block) or isset($Block['type'])or isset($Block['interrupted']))654 { 655 return; 656 } 657 658 if ( chop($Line['text'], $Line['text'][0]) === '')813 if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted'])) 814 { 815 return; 816 } 817 818 if ($Line['indent'] < 4 and chop(chop($Line['text'], ' '), $Line['text'][0]) === '') 659 819 { 660 820 $Block['element']['name'] = $Line['text'][0] === '=' ? 'h1' : 'h2'; … … 669 829 protected function blockMarkup($Line) 670 830 { 671 if ($this->markupEscaped )672 { 673 return; 674 } 675 676 if (preg_match('/^< (\w*)(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*(\/)?>/', $Line['text'], $matches))831 if ($this->markupEscaped or $this->safeMode) 832 { 833 return; 834 } 835 836 if (preg_match('/^<[\/]?+(\w*)(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+(\/)?>/', $Line['text'], $matches)) 677 837 { 678 838 $element = strtolower($matches[1]); … … 685 845 $Block = array( 686 846 'name' => $matches[1], 687 'depth' => 0, 688 'markup' => $Line['text'], 689 ); 690 691 $length = strlen($matches[0]); 692 693 $remainder = substr($Line['text'], $length); 694 695 if (trim($remainder) === '') 696 { 697 if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) 698 { 699 $Block['closed'] = true; 700 701 $Block['void'] = true; 702 } 703 } 704 else 705 { 706 if (isset($matches[2]) or in_array($matches[1], $this->voidElements)) 707 { 708 return; 709 } 710 711 if (preg_match('/<\/'.$matches[1].'>[ ]*$/i', $remainder)) 712 { 713 $Block['closed'] = true; 714 } 715 } 847 'element' => array( 848 'rawHtml' => $Line['text'], 849 'autobreak' => true, 850 ), 851 ); 716 852 717 853 return $Block; … … 721 857 protected function blockMarkupContinue($Line, array $Block) 722 858 { 723 if (isset($Block['closed'])) 724 { 725 return; 726 } 727 728 if (preg_match('/^<'.$Block['name'].'(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*>/i', $Line['text'])) # open 729 { 730 $Block['depth'] ++; 731 } 732 733 if (preg_match('/(.*?)<\/'.$Block['name'].'>[ ]*$/i', $Line['text'], $matches)) # close 734 { 735 if ($Block['depth'] > 0) 736 { 737 $Block['depth'] --; 738 } 739 else 740 { 741 $Block['closed'] = true; 742 } 743 } 744 745 if (isset($Block['interrupted'])) 746 { 747 $Block['markup'] .= "\n"; 748 749 unset($Block['interrupted']); 750 } 751 752 $Block['markup'] .= "\n".$Line['body']; 859 if (isset($Block['closed']) or isset($Block['interrupted'])) 860 { 861 return; 862 } 863 864 $Block['element']['rawHtml'] .= "\n" . $Line['body']; 753 865 754 866 return $Block; … … 760 872 protected function blockReference($Line) 761 873 { 762 if (preg_match('/^\[(.+?)\]:[ ]*<?(\S+?)>?(?:[ ]+["\'(](.+)["\')])?[ ]*$/', $Line['text'], $matches)) 763 { 874 if (strpos($Line['text'], ']') !== false 875 and preg_match('/^\[(.+?)\]:[ ]*+<?(\S+?)>?(?:[ ]+["\'(](.+)["\')])?[ ]*+$/', $Line['text'], $matches) 876 ) { 764 877 $id = strtolower($matches[1]); 765 878 766 879 $Data = array( 767 880 'url' => $matches[2], 768 'title' => null, 769 ); 770 771 if (isset($matches[3])) 772 { 773 $Data['title'] = $matches[3]; 774 } 881 'title' => isset($matches[3]) ? $matches[3] : null, 882 ); 775 883 776 884 $this->DefinitionData['Reference'][$id] = $Data; 777 885 778 886 $Block = array( 779 ' hidden' => true,887 'element' => array(), 780 888 ); 781 889 … … 789 897 protected function blockTable($Line, array $Block = null) 790 898 { 791 if ( ! isset($Block) or isset($Block['type']) or isset($Block['interrupted'])) 792 { 793 return; 794 } 795 796 if (strpos($Block['element']['text'], '|') !== false and chop($Line['text'], ' -:|') === '') 797 { 798 $alignments = array(); 799 800 $divider = $Line['text']; 801 802 $divider = trim($divider); 803 $divider = trim($divider, '|'); 804 805 $dividerCells = explode('|', $divider); 806 807 foreach ($dividerCells as $dividerCell) 808 { 809 $dividerCell = trim($dividerCell); 810 811 if ($dividerCell === '') 812 { 813 continue; 814 } 815 816 $alignment = null; 817 818 if ($dividerCell[0] === ':') 819 { 820 $alignment = 'left'; 821 } 822 823 if (substr($dividerCell, - 1) === ':') 824 { 825 $alignment = $alignment === 'left' ? 'center' : 'right'; 826 } 827 828 $alignments []= $alignment; 829 } 830 831 # ~ 832 833 $HeaderElements = array(); 834 835 $header = $Block['element']['text']; 836 837 $header = trim($header); 838 $header = trim($header, '|'); 839 840 $headerCells = explode('|', $header); 841 842 foreach ($headerCells as $index => $headerCell) 843 { 844 $headerCell = trim($headerCell); 845 846 $HeaderElement = array( 847 'name' => 'th', 848 'text' => $headerCell, 849 'handler' => 'line', 899 if ( ! isset($Block) or $Block['type'] !== 'Paragraph' or isset($Block['interrupted'])) 900 { 901 return; 902 } 903 904 if ( 905 strpos($Block['element']['handler']['argument'], '|') === false 906 and strpos($Line['text'], '|') === false 907 and strpos($Line['text'], ':') === false 908 or strpos($Block['element']['handler']['argument'], "\n") !== false 909 ) { 910 return; 911 } 912 913 if (chop($Line['text'], ' -:|') !== '') 914 { 915 return; 916 } 917 918 $alignments = array(); 919 920 $divider = $Line['text']; 921 922 $divider = trim($divider); 923 $divider = trim($divider, '|'); 924 925 $dividerCells = explode('|', $divider); 926 927 foreach ($dividerCells as $dividerCell) 928 { 929 $dividerCell = trim($dividerCell); 930 931 if ($dividerCell === '') 932 { 933 return; 934 } 935 936 $alignment = null; 937 938 if ($dividerCell[0] === ':') 939 { 940 $alignment = 'left'; 941 } 942 943 if (substr($dividerCell, - 1) === ':') 944 { 945 $alignment = $alignment === 'left' ? 'center' : 'right'; 946 } 947 948 $alignments []= $alignment; 949 } 950 951 # ~ 952 953 $HeaderElements = array(); 954 955 $header = $Block['element']['handler']['argument']; 956 957 $header = trim($header); 958 $header = trim($header, '|'); 959 960 $headerCells = explode('|', $header); 961 962 if (count($headerCells) !== count($alignments)) 963 { 964 return; 965 } 966 967 foreach ($headerCells as $index => $headerCell) 968 { 969 $headerCell = trim($headerCell); 970 971 $HeaderElement = array( 972 'name' => 'th', 973 'handler' => array( 974 'function' => 'lineElements', 975 'argument' => $headerCell, 976 'destination' => 'elements', 977 ) 978 ); 979 980 if (isset($alignments[$index])) 981 { 982 $alignment = $alignments[$index]; 983 984 $HeaderElement['attributes'] = array( 985 'style' => "text-align: $alignment;", 850 986 ); 851 852 if (isset($alignments[$index])) 853 { 854 $alignment = $alignments[$index]; 855 856 $HeaderElement['attributes'] = array( 857 'style' => 'text-align: '.$alignment.';', 858 ); 859 } 860 861 $HeaderElements []= $HeaderElement; 862 } 863 864 # ~ 865 866 $Block = array( 867 'alignments' => $alignments, 868 'identified' => true, 869 'element' => array( 870 'name' => 'table', 871 'handler' => 'elements', 872 ), 873 ); 874 875 $Block['element']['text'] []= array( 876 'name' => 'thead', 877 'handler' => 'elements', 878 ); 879 880 $Block['element']['text'] []= array( 881 'name' => 'tbody', 882 'handler' => 'elements', 883 'text' => array(), 884 ); 885 886 $Block['element']['text'][0]['text'] []= array( 887 'name' => 'tr', 888 'handler' => 'elements', 889 'text' => $HeaderElements, 890 ); 891 892 return $Block; 893 } 987 } 988 989 $HeaderElements []= $HeaderElement; 990 } 991 992 # ~ 993 994 $Block = array( 995 'alignments' => $alignments, 996 'identified' => true, 997 'element' => array( 998 'name' => 'table', 999 'elements' => array(), 1000 ), 1001 ); 1002 1003 $Block['element']['elements'] []= array( 1004 'name' => 'thead', 1005 ); 1006 1007 $Block['element']['elements'] []= array( 1008 'name' => 'tbody', 1009 'elements' => array(), 1010 ); 1011 1012 $Block['element']['elements'][0]['elements'] []= array( 1013 'name' => 'tr', 1014 'elements' => $HeaderElements, 1015 ); 1016 1017 return $Block; 894 1018 } 895 1019 … … 901 1025 } 902 1026 903 if ( $Line['text'][0] === '|' or strpos($Line['text'], '|'))1027 if (count($Block['alignments']) === 1 or $Line['text'][0] === '|' or strpos($Line['text'], '|')) 904 1028 { 905 1029 $Elements = array(); … … 910 1034 $row = trim($row, '|'); 911 1035 912 preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/', $row, $matches); 913 914 foreach ($matches[0] as $index => $cell) 1036 preg_match_all('/(?:(\\\\[|])|[^|`]|`[^`]++`|`)++/', $row, $matches); 1037 1038 $cells = array_slice($matches[0], 0, count($Block['alignments'])); 1039 1040 foreach ($cells as $index => $cell) 915 1041 { 916 1042 $cell = trim($cell); … … 918 1044 $Element = array( 919 1045 'name' => 'td', 920 'handler' => 'line', 921 'text' => $cell, 1046 'handler' => array( 1047 'function' => 'lineElements', 1048 'argument' => $cell, 1049 'destination' => 'elements', 1050 ) 922 1051 ); 923 1052 … … 925 1054 { 926 1055 $Element['attributes'] = array( 927 'style' => 'text-align: ' .$Block['alignments'][$index].';',1056 'style' => 'text-align: ' . $Block['alignments'][$index] . ';', 928 1057 ); 929 1058 } … … 934 1063 $Element = array( 935 1064 'name' => 'tr', 936 'handler' => 'elements', 937 'text' => $Elements, 938 ); 939 940 $Block['element']['text'][1]['text'] []= $Element; 1065 'elements' => $Elements, 1066 ); 1067 1068 $Block['element']['elements'][1]['elements'] []= $Element; 941 1069 942 1070 return $Block; … … 950 1078 protected function paragraph($Line) 951 1079 { 952 $Block = array( 1080 return array( 1081 'type' => 'Paragraph', 953 1082 'element' => array( 954 1083 'name' => 'p', 955 'text' => $Line['text'], 956 'handler' => 'line', 1084 'handler' => array( 1085 'function' => 'lineElements', 1086 'argument' => $Line['text'], 1087 'destination' => 'elements', 1088 ), 957 1089 ), 958 1090 ); 1091 } 1092 1093 protected function paragraphContinue($Line, array $Block) 1094 { 1095 if (isset($Block['interrupted'])) 1096 { 1097 return; 1098 } 1099 1100 $Block['element']['handler']['argument'] .= "\n".$Line['text']; 959 1101 960 1102 return $Block; … … 966 1108 967 1109 protected $InlineTypes = array( 968 '"' => array('SpecialCharacter'),969 1110 '!' => array('Image'), 970 1111 '&' => array('SpecialCharacter'), 971 1112 '*' => array('Emphasis'), 972 1113 ':' => array('Url'), 973 '<' => array('UrlTag', 'EmailTag', 'Markup', 'SpecialCharacter'), 974 '>' => array('SpecialCharacter'), 1114 '<' => array('UrlTag', 'EmailTag', 'Markup'), 975 1115 '[' => array('Link'), 976 1116 '_' => array('Emphasis'), … … 982 1122 # ~ 983 1123 984 protected $inlineMarkerList = '! "*_&[:<>`~\\';1124 protected $inlineMarkerList = '!*_&[:<`~\\'; 985 1125 986 1126 # … … 988 1128 # 989 1129 990 public function line($text) 991 { 992 $markup = ''; 1130 public function line($text, $nonNestables = array()) 1131 { 1132 return $this->elements($this->lineElements($text, $nonNestables)); 1133 } 1134 1135 protected function lineElements($text, $nonNestables = array()) 1136 { 1137 # standardize line breaks 1138 $text = str_replace(array("\r\n", "\r"), "\n", $text); 1139 1140 $Elements = array(); 1141 1142 $nonNestables = (empty($nonNestables) 1143 ? array() 1144 : array_combine($nonNestables, $nonNestables) 1145 ); 993 1146 994 1147 # $excerpt is based on the first occurrence of a marker … … 998 1151 $marker = $excerpt[0]; 999 1152 1000 $markerPosition = str pos($text, $marker);1153 $markerPosition = strlen($text) - strlen($excerpt); 1001 1154 1002 1155 $Excerpt = array('text' => $excerpt, 'context' => $text); … … 1004 1157 foreach ($this->InlineTypes[$marker] as $inlineType) 1005 1158 { 1006 $Inline = $this->{'inline'.$inlineType}($Excerpt); 1159 # check to see if the current inline type is nestable in the current context 1160 1161 if (isset($nonNestables[$inlineType])) 1162 { 1163 continue; 1164 } 1165 1166 $Inline = $this->{"inline$inlineType"}($Excerpt); 1007 1167 1008 1168 if ( ! isset($Inline)) … … 1025 1185 } 1026 1186 1187 # cause the new element to 'inherit' our non nestables 1188 1189 1190 $Inline['element']['nonNestables'] = isset($Inline['element']['nonNestables']) 1191 ? array_merge($Inline['element']['nonNestables'], $nonNestables) 1192 : $nonNestables 1193 ; 1194 1027 1195 # the text that comes before the inline 1028 1196 $unmarkedText = substr($text, 0, $Inline['position']); 1029 1197 1030 1198 # compile the unmarked text 1031 $markup .= $this->unmarkedText($unmarkedText); 1199 $InlineText = $this->inlineText($unmarkedText); 1200 $Elements[] = $InlineText['element']; 1032 1201 1033 1202 # compile the inline 1034 $ markup .= isset($Inline['markup']) ? $Inline['markup'] : $this->element($Inline['element']);1203 $Elements[] = $this->extractElement($Inline); 1035 1204 1036 1205 # remove the examined text … … 1044 1213 $unmarkedText = substr($text, 0, $markerPosition + 1); 1045 1214 1046 $markup .= $this->unmarkedText($unmarkedText); 1215 $InlineText = $this->inlineText($unmarkedText); 1216 $Elements[] = $InlineText['element']; 1047 1217 1048 1218 $text = substr($text, $markerPosition + 1); 1049 1219 } 1050 1220 1051 $markup .= $this->unmarkedText($text); 1052 1053 return $markup; 1221 $InlineText = $this->inlineText($text); 1222 $Elements[] = $InlineText['element']; 1223 1224 foreach ($Elements as &$Element) 1225 { 1226 if ( ! isset($Element['autobreak'])) 1227 { 1228 $Element['autobreak'] = false; 1229 } 1230 } 1231 1232 return $Elements; 1054 1233 } 1055 1234 … … 1058 1237 # 1059 1238 1239 protected function inlineText($text) 1240 { 1241 $Inline = array( 1242 'extent' => strlen($text), 1243 'element' => array(), 1244 ); 1245 1246 $Inline['element']['elements'] = self::pregReplaceElements( 1247 $this->breaksEnabled ? '/[ ]*+\n/' : '/(?:[ ]*+\\\\|[ ]{2,}+)\n/', 1248 array( 1249 array('name' => 'br'), 1250 array('text' => "\n"), 1251 ), 1252 $text 1253 ); 1254 1255 return $Inline; 1256 } 1257 1060 1258 protected function inlineCode($Excerpt) 1061 1259 { 1062 1260 $marker = $Excerpt['text'][0]; 1063 1261 1064 if (preg_match('/^( '.$marker.'+)[ ]*(.+?)[ ]*(?<!'.$marker.')\1(?!'.$marker.')/s', $Excerpt['text'], $matches))1262 if (preg_match('/^(['.$marker.']++)[ ]*+(.+?)[ ]*+(?<!['.$marker.'])\1(?!'.$marker.')/s', $Excerpt['text'], $matches)) 1065 1263 { 1066 1264 $text = $matches[2]; 1067 $text = htmlspecialchars($text, ENT_NOQUOTES, 'UTF-8'); 1068 $text = preg_replace("/[ ]*\n/", ' ', $text); 1265 $text = preg_replace('/[ ]*+\n/', ' ', $text); 1069 1266 1070 1267 return array( … … 1080 1277 protected function inlineEmailTag($Excerpt) 1081 1278 { 1082 if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<((mailto:)?\S+?@\S+?)>/i', $Excerpt['text'], $matches)) 1083 { 1279 $hostnameLabel = '[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?'; 1280 1281 $commonMarkEmail = '[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]++@' 1282 . $hostnameLabel . '(?:\.' . $hostnameLabel . ')*'; 1283 1284 if (strpos($Excerpt['text'], '>') !== false 1285 and preg_match("/^<((mailto:)?$commonMarkEmail)>/i", $Excerpt['text'], $matches) 1286 ){ 1084 1287 $url = $matches[1]; 1085 1288 1086 1289 if ( ! isset($matches[2])) 1087 1290 { 1088 $url = 'mailto:' . $url;1291 $url = "mailto:$url"; 1089 1292 } 1090 1293 … … 1128 1331 'element' => array( 1129 1332 'name' => $emphasis, 1130 'handler' => 'line', 1131 'text' => $matches[1], 1333 'handler' => array( 1334 'function' => 'lineElements', 1335 'argument' => $matches[1], 1336 'destination' => 'elements', 1337 ) 1132 1338 ), 1133 1339 ); … … 1139 1345 { 1140 1346 return array( 1141 ' markup' => $Excerpt['text'][1],1347 'element' => array('rawHtml' => $Excerpt['text'][1]), 1142 1348 'extent' => 2, 1143 1349 ); … … 1167 1373 'attributes' => array( 1168 1374 'src' => $Link['element']['attributes']['href'], 1169 'alt' => $Link['element'][' text'],1375 'alt' => $Link['element']['handler']['argument'], 1170 1376 ), 1377 'autobreak' => true, 1171 1378 ), 1172 1379 ); … … 1183 1390 $Element = array( 1184 1391 'name' => 'a', 1185 'handler' => 'line', 1186 'text' => null, 1392 'handler' => array( 1393 'function' => 'lineElements', 1394 'argument' => null, 1395 'destination' => 'elements', 1396 ), 1397 'nonNestables' => array('Url', 'Link'), 1187 1398 'attributes' => array( 1188 1399 'href' => null, … … 1195 1406 $remainder = $Excerpt['text']; 1196 1407 1197 if (preg_match('/\[((?:[^][] |(?R))*)\]/', $remainder, $matches))1198 { 1199 $Element[' text'] = $matches[1];1408 if (preg_match('/\[((?:[^][]++|(?R))*+)\]/', $remainder, $matches)) 1409 { 1410 $Element['handler']['argument'] = $matches[1]; 1200 1411 1201 1412 $extent += strlen($matches[0]); … … 1208 1419 } 1209 1420 1210 if (preg_match('/^[(] ((?:[^ ()]|[(][^ )]+[)])+)(?:[ ]+("[^"]*"|\'[^\']*\'))?[)]/', $remainder, $matches))1421 if (preg_match('/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*+"|\'[^\']*+\'))?\s*+[)]/', $remainder, $matches)) 1211 1422 { 1212 1423 $Element['attributes']['href'] = $matches[1]; … … 1223 1434 if (preg_match('/^\s*\[(.*?)\]/', $remainder, $matches)) 1224 1435 { 1225 $definition = strlen($matches[1]) ? $matches[1] : $Element[' text'];1436 $definition = strlen($matches[1]) ? $matches[1] : $Element['handler']['argument']; 1226 1437 $definition = strtolower($definition); 1227 1438 … … 1230 1441 else 1231 1442 { 1232 $definition = strtolower($Element[' text']);1443 $definition = strtolower($Element['handler']['argument']); 1233 1444 } 1234 1445 … … 1243 1454 $Element['attributes']['title'] = $Definition['title']; 1244 1455 } 1245 1246 $Element['attributes']['href'] = str_replace(array('&', '<'), array('&', '<'), $Element['attributes']['href']);1247 1456 1248 1457 return array( … … 1254 1463 protected function inlineMarkup($Excerpt) 1255 1464 { 1256 if ($this->markupEscaped or strpos($Excerpt['text'], '>') === false)1257 { 1258 return; 1259 } 1260 1261 if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w *[ ]*>/s', $Excerpt['text'], $matches))1465 if ($this->markupEscaped or $this->safeMode or strpos($Excerpt['text'], '>') === false) 1466 { 1467 return; 1468 } 1469 1470 if ($Excerpt['text'][1] === '/' and preg_match('/^<\/\w[\w-]*+[ ]*+>/s', $Excerpt['text'], $matches)) 1262 1471 { 1263 1472 return array( 1264 ' markup' => $matches[0],1473 'element' => array('rawHtml' => $matches[0]), 1265 1474 'extent' => strlen($matches[0]), 1266 1475 ); 1267 1476 } 1268 1477 1269 if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-? [^-])*-->/s', $Excerpt['text'], $matches))1478 if ($Excerpt['text'][1] === '!' and preg_match('/^<!---?[^>-](?:-?+[^-])*-->/s', $Excerpt['text'], $matches)) 1270 1479 { 1271 1480 return array( 1272 ' markup' => $matches[0],1481 'element' => array('rawHtml' => $matches[0]), 1273 1482 'extent' => strlen($matches[0]), 1274 1483 ); 1275 1484 } 1276 1485 1277 if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w *(?:[ ]*'.$this->regexHtmlAttribute.')*[ ]*\/?>/s', $Excerpt['text'], $matches))1486 if ($Excerpt['text'][1] !== ' ' and preg_match('/^<\w[\w-]*+(?:[ ]*+'.$this->regexHtmlAttribute.')*+[ ]*+\/?>/s', $Excerpt['text'], $matches)) 1278 1487 { 1279 1488 return array( 1280 ' markup' => $matches[0],1489 'element' => array('rawHtml' => $matches[0]), 1281 1490 'extent' => strlen($matches[0]), 1282 1491 ); … … 1286 1495 protected function inlineSpecialCharacter($Excerpt) 1287 1496 { 1288 if ($Excerpt['text'][0] === '&' and ! preg_match('/^&#?\w+;/', $Excerpt['text'])) 1289 { 1497 if (substr($Excerpt['text'], 1, 1) !== ' ' and strpos($Excerpt['text'], ';') !== false 1498 and preg_match('/^&(#?+[0-9a-zA-Z]++);/', $Excerpt['text'], $matches) 1499 ) { 1290 1500 return array( 1291 'markup' => '&', 1292 'extent' => 1, 1293 ); 1294 } 1295 1296 $SpecialCharacter = array('>' => 'gt', '<' => 'lt', '"' => 'quot'); 1297 1298 if (isset($SpecialCharacter[$Excerpt['text'][0]])) 1299 { 1300 return array( 1301 'markup' => '&'.$SpecialCharacter[$Excerpt['text'][0]].';', 1302 'extent' => 1, 1303 ); 1304 } 1501 'element' => array('rawHtml' => '&' . $matches[1] . ';'), 1502 'extent' => strlen($matches[0]), 1503 ); 1504 } 1505 1506 return; 1305 1507 } 1306 1508 … … 1318 1520 'element' => array( 1319 1521 'name' => 'del', 1320 'text' => $matches[1], 1321 'handler' => 'line', 1522 'handler' => array( 1523 'function' => 'lineElements', 1524 'argument' => $matches[1], 1525 'destination' => 'elements', 1526 ) 1322 1527 ), 1323 1528 ); … … 1332 1537 } 1333 1538 1334 if (preg_match('/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE)) 1335 { 1539 if (strpos($Excerpt['context'], 'http') !== false 1540 and preg_match('/\bhttps?+:[\/]{2}[^\s<]+\b\/*+/ui', $Excerpt['context'], $matches, PREG_OFFSET_CAPTURE) 1541 ) { 1542 $url = $matches[0][0]; 1543 1336 1544 $Inline = array( 1337 1545 'extent' => strlen($matches[0][0]), … … 1339 1547 'element' => array( 1340 1548 'name' => 'a', 1341 'text' => $ matches[0][0],1549 'text' => $url, 1342 1550 'attributes' => array( 1343 'href' => $ matches[0][0],1551 'href' => $url, 1344 1552 ), 1345 1553 ), … … 1352 1560 protected function inlineUrlTag($Excerpt) 1353 1561 { 1354 if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w+ :\/{2}[^ >]+)>/i', $Excerpt['text'], $matches))1355 { 1356 $url = str_replace(array('&', '<'), array('&', '<'), $matches[1]);1562 if (strpos($Excerpt['text'], '>') !== false and preg_match('/^<(\w++:\/{2}[^ >]++)>/i', $Excerpt['text'], $matches)) 1563 { 1564 $url = $matches[1]; 1357 1565 1358 1566 return array( … … 1373 1581 protected function unmarkedText($text) 1374 1582 { 1375 if ($this->breaksEnabled) 1376 { 1377 $text = preg_replace('/[ ]*\n/', "<br />\n", $text); 1583 $Inline = $this->inlineText($text); 1584 return $this->element($Inline['element']); 1585 } 1586 1587 # 1588 # Handlers 1589 # 1590 1591 protected function handle(array $Element) 1592 { 1593 if (isset($Element['handler'])) 1594 { 1595 if (!isset($Element['nonNestables'])) 1596 { 1597 $Element['nonNestables'] = array(); 1598 } 1599 1600 if (is_string($Element['handler'])) 1601 { 1602 $function = $Element['handler']; 1603 $argument = $Element['text']; 1604 unset($Element['text']); 1605 $destination = 'rawHtml'; 1606 } 1607 else 1608 { 1609 $function = $Element['handler']['function']; 1610 $argument = $Element['handler']['argument']; 1611 $destination = $Element['handler']['destination']; 1612 } 1613 1614 $Element[$destination] = $this->{$function}($argument, $Element['nonNestables']); 1615 1616 if ($destination === 'handler') 1617 { 1618 $Element = $this->handle($Element); 1619 } 1620 1621 unset($Element['handler']); 1622 } 1623 1624 return $Element; 1625 } 1626 1627 protected function handleElementRecursive(array $Element) 1628 { 1629 return $this->elementApplyRecursive(array($this, 'handle'), $Element); 1630 } 1631 1632 protected function handleElementsRecursive(array $Elements) 1633 { 1634 return $this->elementsApplyRecursive(array($this, 'handle'), $Elements); 1635 } 1636 1637 protected function elementApplyRecursive($closure, array $Element) 1638 { 1639 $Element = call_user_func($closure, $Element); 1640 1641 if (isset($Element['elements'])) 1642 { 1643 $Element['elements'] = $this->elementsApplyRecursive($closure, $Element['elements']); 1644 } 1645 elseif (isset($Element['element'])) 1646 { 1647 $Element['element'] = $this->elementApplyRecursive($closure, $Element['element']); 1648 } 1649 1650 return $Element; 1651 } 1652 1653 protected function elementApplyRecursiveDepthFirst($closure, array $Element) 1654 { 1655 if (isset($Element['elements'])) 1656 { 1657 $Element['elements'] = $this->elementsApplyRecursiveDepthFirst($closure, $Element['elements']); 1658 } 1659 elseif (isset($Element['element'])) 1660 { 1661 $Element['element'] = $this->elementsApplyRecursiveDepthFirst($closure, $Element['element']); 1662 } 1663 1664 $Element = call_user_func($closure, $Element); 1665 1666 return $Element; 1667 } 1668 1669 protected function elementsApplyRecursive($closure, array $Elements) 1670 { 1671 foreach ($Elements as &$Element) 1672 { 1673 $Element = $this->elementApplyRecursive($closure, $Element); 1674 } 1675 1676 return $Elements; 1677 } 1678 1679 protected function elementsApplyRecursiveDepthFirst($closure, array $Elements) 1680 { 1681 foreach ($Elements as &$Element) 1682 { 1683 $Element = $this->elementApplyRecursiveDepthFirst($closure, $Element); 1684 } 1685 1686 return $Elements; 1687 } 1688 1689 protected function element(array $Element) 1690 { 1691 if ($this->safeMode) 1692 { 1693 $Element = $this->sanitiseElement($Element); 1694 } 1695 1696 # identity map if element has no handler 1697 $Element = $this->handle($Element); 1698 1699 $hasName = isset($Element['name']); 1700 1701 $markup = ''; 1702 1703 if ($hasName) 1704 { 1705 $markup .= '<' . $Element['name']; 1706 1707 if (isset($Element['attributes'])) 1708 { 1709 foreach ($Element['attributes'] as $name => $value) 1710 { 1711 if ($value === null) 1712 { 1713 continue; 1714 } 1715 1716 $markup .= " $name=\"".self::escape($value).'"'; 1717 } 1718 } 1719 } 1720 1721 $permitRawHtml = false; 1722 1723 if (isset($Element['text'])) 1724 { 1725 $text = $Element['text']; 1726 } 1727 // very strongly consider an alternative if you're writing an 1728 // extension 1729 elseif (isset($Element['rawHtml'])) 1730 { 1731 $text = $Element['rawHtml']; 1732 1733 $allowRawHtmlInSafeMode = isset($Element['allowRawHtmlInSafeMode']) && $Element['allowRawHtmlInSafeMode']; 1734 $permitRawHtml = !$this->safeMode || $allowRawHtmlInSafeMode; 1735 } 1736 1737 $hasContent = isset($text) || isset($Element['element']) || isset($Element['elements']); 1738 1739 if ($hasContent) 1740 { 1741 $markup .= $hasName ? '>' : ''; 1742 1743 if (isset($Element['elements'])) 1744 { 1745 $markup .= $this->elements($Element['elements']); 1746 } 1747 elseif (isset($Element['element'])) 1748 { 1749 $markup .= $this->element($Element['element']); 1750 } 1751 else 1752 { 1753 if (!$permitRawHtml) 1754 { 1755 $markup .= self::escape($text, true); 1756 } 1757 else 1758 { 1759 $markup .= $text; 1760 } 1761 } 1762 1763 $markup .= $hasName ? '</' . $Element['name'] . '>' : ''; 1764 } 1765 elseif ($hasName) 1766 { 1767 $markup .= ' />'; 1768 } 1769 1770 return $markup; 1771 } 1772 1773 protected function elements(array $Elements) 1774 { 1775 $markup = ''; 1776 1777 $autoBreak = true; 1778 1779 foreach ($Elements as $Element) 1780 { 1781 if (empty($Element)) 1782 { 1783 continue; 1784 } 1785 1786 $autoBreakNext = (isset($Element['autobreak']) 1787 ? $Element['autobreak'] : isset($Element['name']) 1788 ); 1789 // (autobreak === false) covers both sides of an element 1790 $autoBreak = !$autoBreak ? $autoBreak : $autoBreakNext; 1791 1792 $markup .= ($autoBreak ? "\n" : '') . $this->element($Element); 1793 $autoBreak = $autoBreakNext; 1794 } 1795 1796 $markup .= $autoBreak ? "\n" : ''; 1797 1798 return $markup; 1799 } 1800 1801 # ~ 1802 1803 protected function li($lines) 1804 { 1805 $Elements = $this->linesElements($lines); 1806 1807 if ( ! in_array('', $lines) 1808 and isset($Elements[0]) and isset($Elements[0]['name']) 1809 and $Elements[0]['name'] === 'p' 1810 ) { 1811 unset($Elements[0]['name']); 1812 } 1813 1814 return $Elements; 1815 } 1816 1817 # 1818 # AST Convenience 1819 # 1820 1821 /** 1822 * Replace occurrences $regexp with $Elements in $text. Return an array of 1823 * elements representing the replacement. 1824 */ 1825 protected static function pregReplaceElements($regexp, $Elements, $text) 1826 { 1827 $newElements = array(); 1828 1829 while (preg_match($regexp, $text, $matches, PREG_OFFSET_CAPTURE)) 1830 { 1831 $offset = $matches[0][1]; 1832 $before = substr($text, 0, $offset); 1833 $after = substr($text, $offset + strlen($matches[0][0])); 1834 1835 $newElements[] = array('text' => $before); 1836 1837 foreach ($Elements as $Element) 1838 { 1839 $newElements[] = $Element; 1840 } 1841 1842 $text = $after; 1843 } 1844 1845 $newElements[] = array('text' => $text); 1846 1847 return $newElements; 1848 } 1849 1850 # 1851 # Deprecated Methods 1852 # 1853 1854 function parse($text) 1855 { 1856 $markup = $this->text($text); 1857 1858 return $markup; 1859 } 1860 1861 protected function sanitiseElement(array $Element) 1862 { 1863 static $goodAttribute = '/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/'; 1864 static $safeUrlNameToAtt = array( 1865 'a' => 'href', 1866 'img' => 'src', 1867 ); 1868 1869 if ( ! isset($Element['name'])) 1870 { 1871 unset($Element['attributes']); 1872 return $Element; 1873 } 1874 1875 if (isset($safeUrlNameToAtt[$Element['name']])) 1876 { 1877 $Element = $this->filterUnsafeUrlInAttribute($Element, $safeUrlNameToAtt[$Element['name']]); 1878 } 1879 1880 if ( ! empty($Element['attributes'])) 1881 { 1882 foreach ($Element['attributes'] as $att => $val) 1883 { 1884 # filter out badly parsed attribute 1885 if ( ! preg_match($goodAttribute, $att)) 1886 { 1887 unset($Element['attributes'][$att]); 1888 } 1889 # dump onevent attribute 1890 elseif (self::striAtStart($att, 'on')) 1891 { 1892 unset($Element['attributes'][$att]); 1893 } 1894 } 1895 } 1896 1897 return $Element; 1898 } 1899 1900 protected function filterUnsafeUrlInAttribute(array $Element, $attribute) 1901 { 1902 foreach ($this->safeLinksWhitelist as $scheme) 1903 { 1904 if (self::striAtStart($Element['attributes'][$attribute], $scheme)) 1905 { 1906 return $Element; 1907 } 1908 } 1909 1910 $Element['attributes'][$attribute] = str_replace(':', '%3A', $Element['attributes'][$attribute]); 1911 1912 return $Element; 1913 } 1914 1915 # 1916 # Static Methods 1917 # 1918 1919 protected static function escape($text, $allowQuotes = false) 1920 { 1921 return htmlspecialchars($text, $allowQuotes ? ENT_NOQUOTES : ENT_QUOTES, 'UTF-8'); 1922 } 1923 1924 protected static function striAtStart($string, $needle) 1925 { 1926 $len = strlen($needle); 1927 1928 if ($len > strlen($string)) 1929 { 1930 return false; 1378 1931 } 1379 1932 else 1380 1933 { 1381 $text = preg_replace('/(?:[ ][ ]+|[ ]*\\\\)\n/', "<br />\n", $text); 1382 $text = str_replace(" \n", "\n", $text); 1383 } 1384 1385 return $text; 1386 } 1387 1388 # 1389 # Handlers 1390 # 1391 1392 protected function element(array $Element) 1393 { 1394 $markup = '<'.$Element['name']; 1395 1396 if (isset($Element['attributes'])) 1397 { 1398 foreach ($Element['attributes'] as $name => $value) 1399 { 1400 if ($value === null) 1401 { 1402 continue; 1403 } 1404 1405 $markup .= ' '.$name.'="'.$value.'"'; 1406 } 1407 } 1408 1409 if (isset($Element['text'])) 1410 { 1411 $markup .= '>'; 1412 1413 if (isset($Element['handler'])) 1414 { 1415 $markup .= $this->{$Element['handler']}($Element['text']); 1416 } 1417 else 1418 { 1419 $markup .= $Element['text']; 1420 } 1421 1422 $markup .= '</'.$Element['name'].'>'; 1423 } 1424 else 1425 { 1426 $markup .= ' />'; 1427 } 1428 1429 return $markup; 1430 } 1431 1432 protected function elements(array $Elements) 1433 { 1434 $markup = ''; 1435 1436 foreach ($Elements as $Element) 1437 { 1438 $markup .= "\n" . $this->element($Element); 1439 } 1440 1441 $markup .= "\n"; 1442 1443 return $markup; 1444 } 1445 1446 # ~ 1447 1448 protected function li($lines) 1449 { 1450 $markup = $this->lines($lines); 1451 1452 $trimmedMarkup = trim($markup); 1453 1454 if ( ! in_array('', $lines) and substr($trimmedMarkup, 0, 3) === '<p>') 1455 { 1456 $markup = $trimmedMarkup; 1457 $markup = substr($markup, 3); 1458 1459 $position = strpos($markup, "</p>"); 1460 1461 $markup = substr_replace($markup, '', $position, 4); 1462 } 1463 1464 return $markup; 1465 } 1466 1467 # 1468 # Deprecated Methods 1469 # 1470 1471 function parse($text) 1472 { 1473 $markup = $this->text($text); 1474 1475 return $markup; 1476 } 1477 1478 # 1479 # Static Methods 1480 # 1934 return strtolower(substr($string, 0, $len)) === strtolower($needle); 1935 } 1936 } 1481 1937 1482 1938 static function instance($name = 'default') … … 1506 1962 1507 1963 protected $specialCharacters = array( 1508 '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', 1964 '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', '~' 1509 1965 ); 1510 1966 1511 1967 protected $StrongRegex = array( 1512 '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]* [*])+?)[*]{2}(?![*])/s',1513 '_' => '/^__((?:\\\\_|[^_]|_[^_]* _)+?)__(?!_)/us',1968 '*' => '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*+[*])+?)[*]{2}(?![*])/s', 1969 '_' => '/^__((?:\\\\_|[^_]|_[^_]*+_)+?)__(?!_)/us', 1514 1970 ); 1515 1971 … … 1519 1975 ); 1520 1976 1521 protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]* (?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?';1977 protected $regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*+(?:\s*+=\s*+(?:[^"\'=<>`\s]+|"[^"]*+"|\'[^\']*+\'))?+'; 1522 1978 1523 1979 protected $voidElements = array( … … 1530 1986 'i', 'rp', 'del', 'code', 'strike', 'marquee', 1531 1987 'q', 'rt', 'ins', 'font', 'strong', 1532 's', 'tt', ' sub', 'mark',1533 'u', 'xm', 'su p', 'nobr',1534 ' var', 'ruby',1535 ' wbr', 'span',1536 'time',1988 's', 'tt', 'kbd', 'mark', 1989 'u', 'xm', 'sub', 'nobr', 1990 'sup', 'ruby', 1991 'var', 'span', 1992 'wbr', 'time', 1537 1993 ); 1538 1994 } -
hosted-content-importer/trunk/hosted-content-importer.php
r1434331 r2149939 3 3 * Plugin Name: Hosted Content Importer (HCI) 4 4 * Plugin URI: https://wordpress.org/plugins/hosted-content-importer/ 5 * Description: Embeds third party contents . Usage: <code>[third source="markdown" id="URL" section=""]</code>5 * Description: Embeds third party contents within your blog. Usage: <code>[third source="markdown" id="URL" section=""]</code>. 6 6 * Author: Bimal Poudel 7 7 * Author URI: http://bimal.org.np/ 8 * Development URI: https://github.com/ bimalpoudel/hosted-content-importer/9 * License: GPLv2 or later10 * Version: 3.0. 18 * Development URI: https://github.com/anytizer/hosted-content-importer.wp/ 9 * License: MIT 10 * Version: 3.0.2 11 11 */ 12 12 … … 14 14 * Cached file validity duration: seconds(Hour+Minutes+Seconds) 15 15 */ 16 define( 'HCI_CACHE_DURATION', 5 * 60 * 60 + 0 * 60 + 0);16 define("HCI_CACHE_DURATION", 5 * 60 * 60 + 0 * 60 + 0); 17 17 18 18 /** 19 19 * Do NOT edit 20 20 */ 21 define( 'HCI_PLUGIN_DIR', dirname(__FILE__));21 define("HCI_PLUGIN_DIR", dirname(__FILE__)); 22 22 23 23 /** … … 25 25 * https://github.com/erusev/parsedown 26 26 */ 27 if(!class_exists( 'Parsedown'))27 if(!class_exists("Parsedown")) 28 28 { 29 require_once (HCI_PLUGIN_DIR . '/classes/parsedown/Parsedown.php');29 require_once HCI_PLUGIN_DIR . "/classes/parsedown/Parsedown.php"; 30 30 } 31 31 … … 33 33 * Main binder 34 34 */ 35 require_once (HCI_PLUGIN_DIR . '/classes/hci/interface.hosted_content_interface.inc.php');36 require_once (HCI_PLUGIN_DIR . '/classes/hci/class.hosted_content_importer.inc.php');35 require_once HCI_PLUGIN_DIR . "/classes/hci/interface.hosted_content_interface.inc.php"; 36 require_once HCI_PLUGIN_DIR . "/classes/hci/class.hosted_content_importer.inc.php"; 37 37 38 38 /** 39 * Install WordPress Shortcodes Handler40 * Install report page41 * Install menus39 * Installs WordPress Shortcodes Handler 40 * Installs report page 41 * Installs menus 42 42 */ 43 require_once (HCI_PLUGIN_DIR . '/classes/hci/class.hosted_content_shortcode.inc.php');43 require_once HCI_PLUGIN_DIR . "/classes/hci/class.hosted_content_shortcode.inc.php"; 44 44 new hosted_content_shortcode(); -
hosted-content-importer/trunk/readme.txt
r1814939 r2149939 2 2 3 3 Contributors: pbimal 4 Donate link: http://bimal.org.np/4 Donate Link: http://bimal.org.np/ 5 5 Tags: cached, content, embed, external, gist, hci, hosted, import, markdown, remote, shortcode, third 6 Requires at least: 4. 5.07 Tested up to: 4.9. 26 Requires at least: 4.0.0 7 Tested up to: 4.9.5 8 8 Stable tag: 3.0.1 9 9 License: GPLv3 or later … … 16 16 == Description == 17 17 18 It imports third party hosted contents within WordPress blog texts. You define from which url/resource to fetch the content. The source may be editable by anyone else whom you trust. Thus, it logically empowers you to allow other users to externally edit a particular section of your blogs. And, you do not have to give them any access toyour website.18 It imports third party hosted contents within WordPress blog. You can define from which url/resource to fetch the content. The original source may be editable by anyone else whom you trust. Thus, it logically empowers you to allow other users to externally edit a particular section of your blogs. And, you do not have to give them any access credentials of your website. 19 19 20 20 After installation, use shortcode tag `[third]` with few parameters as: 21 21 22 22 `[third source="markdown" id="https://goo.gl/UpclKH" section=""]` 23 24 * `source` is a content processor type. 25 * `id` is a URL or ID given by the third parties. 26 * `section` is an optional parameter to access deeper content. 27 * `cache` is a boolean directive whether to reuse the cached content. 28 23 29 24 30 It will then embed remote markdown content inside your blog. … … 79 85 `[third source="file" id="/tmp/readme.txt" section=""]` 80 86 81 It has tto be a static file for security reasons. For example, if you read the .php file, it will NOT process it, rather read its contents only. Your can contain valid HTML data, css and javascripts.87 It has to be a static file for security reasons. For example, if you read the .php file, it will NOT process it, rather read its contents only. Your can contain valid HTML data, css and javascripts. 82 88 83 89 … … 209 215 Please view the original development at: https://goo.gl/89KgSC for details and further plans. 210 216 217 = 3.0.2 = 218 * Parsedown upgraded. 219 * Typos corrections. 220 211 221 = 3.0.1 = 212 * TinyMCE Plugin and text mode tags inserteradded.222 * TinyMCE Plugin and text mode editor plgins added. 213 223 * As-Is request for not wrapping the HTML Output within HCI divs. 214 224 * Experimental: Dumped handlers or registered shortcodes.
Note: See TracChangeset
for help on using the changeset viewer.