/** * @covers \PressBooks\Sanitize\remove_control_characters */ public function test_remove_control_characters() { $var = "Hello-World!"; $test = $this->_generateControlCharacters() . $var; $test = \PressBooks\Sanitize\remove_control_characters($test); $this->assertEquals(12, strlen($test)); $var = "Héllö Wôrld!"; $test = \PressBooks\Sanitize\remove_control_characters($var); $this->assertEquals(12, mb_strlen($test, 'UTF-8')); $var = "こんにちは世界!"; $test = \PressBooks\Sanitize\remove_control_characters($var); $this->assertEquals(8, mb_strlen($test, 'UTF-8')); }
/** * WP_Ajax hook. Convert MS Word footnotes to Pressbooks compatible [footnotes] */ static function convertWordFootnotes() { if (!current_user_can('edit_posts') || !check_ajax_referer('pb-footnote-convert', false, false)) { static::ajaxFailure(__('Invalid permissions.', 'pressbooks')); } $html = urldecode(stripslashes($_POST['content'])); /** * Regular expression tip: * (?: ), in contrast to ( ), is used to avoid capturing text. * * A $pattern must capture: * [0] => ... full capture ... * [1] => #_ftnref130 * [2] => 130 * [3] => ... the text we want to move ... * * Known MS Word variations: * href="#_ftn123" (-> #_ftnref123) * href="#_edn123" (-> #_ednref123) * href="/Users/foo/Documents/bar/9781426766497.doc#_ftn123" (-> .doc#_ftnref123) * href="/Users/foo/Documents/bar/9781426766497.docx#_edn123" (-> .docx#_ednref123) * * Known Libre Office variations: * href="#sdfootnote123sym" (-> #sdfootnote123anc) */ $patterns = array('~<a[\\s]+[^>]*?href[\\s]?=[\\s"\']+(#_ftnref([0-9]+))["\']+.*?>(?:[^<]+|.*?)?</a>(.*?)</div>~si', '~<a[\\s]+[^>]*?href[\\s]?=[\\s"\']+.*?[\\.doc|\\.docx](#_ftnref([0-9]+))["\']+.*?>(?:[^<]+|.*?)?</a>(.*?)</div>~si', '~<a[\\s]+[^>]*?href[\\s]?=[\\s"\']+(#_ednref([0-9]+))["\']+.*?>(?:[^<]+|.*?)?</a>(.*?)</div>~si', '~<a[\\s]+[^>]*?href[\\s]?=[\\s"\']+.*?[\\.doc|\\.docx](#_ednref([0-9]+))["\']+.*?>(?:[^<]+|.*?)?</a>(.*?)</div>~si', '~<a[\\s]+[^>]*?href[\\s]?=[\\s"\']+(#sdfootnote([0-9]+)anc)["\']+.*?>(?:[^<]+|.*?)?</a>(.*?)</div>~si'); /** * A $replacer must be in the same position as a corresponding $pattern above, * use __REPLACE_ME__ to substitute for what we don't know yet. */ $replacers = array('~<a[\\s]+[^>]*?href[\\s]?=[\\s"\']+(?:#_ftn__REPLACE_ME__)["\']+.*?>(?:[^<]+|.*?)?</a>~si', '~<a[\\s]+[^>]*?href[\\s]?=[\\s"\']+.*?[\\.doc|\\.docx](?:#_ftn__REPLACE_ME__)["\']+.*?>(?:[^<]+|.*?)?</a>~si', '~<a[\\s]+[^>]*?href[\\s]?=[\\s"\']+(?:#_edn__REPLACE_ME__)["\']+.*?>(?:[^<]+|.*?)?</a>~si', '~<a[\\s]+[^>]*?href[\\s]?=[\\s"\']+.*?[\\.doc|\\.docx](?:#_edn__REPLACE_ME__)["\']+.*?>(?:[^<]+|.*?)?</a>~si', '~<a[\\s]+[^>]*?href[\\s]?=[\\s"\']+(?:#sdfootnote__REPLACE_ME__sym)["\']+.*?>(?:[^<]+|.*?)?</a>~si'); $footnotes = $find = $replace = array(); foreach ($patterns as $i => $pattern) { preg_match_all($pattern, $html, $footnotes, PREG_SET_ORDER); foreach ($footnotes as $footnote) { $tmp = wp_kses($footnote[3], array('b' => array(), 'em' => array(), 'i' => array(), 'strong' => array())); $tmp = \PressBooks\Sanitize\remove_control_characters($tmp); $tmp = trim(preg_replace('/\\s+/', ' ', $tmp)); // Normalize white spaces $find[] = str_replace('__REPLACE_ME__', preg_quote($footnote[2]), $replacers[$i]); $replace[] = '[footnote]' . $tmp . '[/footnote]'; } // Remove originals when done $find[] = $pattern; $replace[] = '…</div>'; } // Twerk it $html = preg_replace($find, $replace, $html); // Important, complex regular expressions have been known to, literally, crash PHP. // When testing, make sure this function exits as expected. // Send back JSON header('Content-Type: application/json'); $json = json_encode(array('content' => $html)); echo $json; // @see http://codex.wordpress.org/AJAX_in_Plugins#Error_Return_Values // Will append 0 to returned json string if we don't die() die; }
/** * Returns book information in a useful, string only, format. Data is converted to HTML. * * @return array */ static function getBookInformation($id = '') { // ----------------------------------------------------------------------------- // Is cached? // ----------------------------------------------------------------------------- if (!empty($id) && is_int($id)) { $blog_id = $id; switch_to_blog($blog_id); } else { global $blog_id; } $cache_id = "book-inf-{$blog_id}"; $book_information = wp_cache_get($cache_id, 'pb'); if ($book_information) { return $book_information; } // ---------------------------------------------------------------------------- // Book Information // ---------------------------------------------------------------------------- $expected_array = array('pb_keywords_tags', 'pb_bisac_subject', 'pb_contributing_authors'); $expected_the_content = array('pb_custom_copyright', 'pb_about_unlimited'); $book_information = array(); $meta = new Metadata(); $data = $meta->getMetaPostMetadata(); foreach ($data as $key => $val) { // Skip anything not prefixed with pb_ if (!preg_match('/^pb_/', $key)) { continue; } // We only care about strings if (is_array($val)) { if (false !== in_array($key, $expected_array)) { $val = implode(', ', $val); } else { $val = array_values($val); $val = array_pop($val); } } // Skip empty values if (!trim($val)) { continue; } if (false !== in_array($key, $expected_the_content)) { $val = wptexturize($val); $val = wpautop($val); } else { $val = htmlspecialchars($val, ENT_NOQUOTES | ENT_XHTML, 'UTF-8', false); } // Remove invisible control characters that break XML $val = \PressBooks\Sanitize\remove_control_characters($val); $book_information[$key] = $val; } // Return our best guess if no book information has been entered. if (empty($book_information)) { $book_information['pb_title'] = get_bloginfo('name'); if (!function_exists('get_user_by')) { include ABSPATH . 'wp-includes/pluggable.php'; } $author = get_user_by('email', get_bloginfo('admin_email')); $book_information['pb_author'] = $author->display_name; $book_information['pb_cover_image'] = \PressBooks\Image\default_cover_url(); } // ----------------------------------------------------------------------------- // Cache & Return // ----------------------------------------------------------------------------- wp_cache_set($cache_id, $book_information, 'pb', 86400); if (!empty($id) && is_int($id)) { restore_current_blog(); } return $book_information; }