ckeditor_php4.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. <?php
  2. /*
  3. * Copyright (c) 2003-2011, CKSource - Frederico Knabben. All rights reserved.
  4. * For licensing, see LICENSE.html or http://ckeditor.com/license
  5. */
  6. /**
  7. * \brief CKEditor class that can be used to create editor
  8. * instances in PHP pages on server side.
  9. * @see http://ckeditor.com
  10. *
  11. * Sample usage:
  12. * @code
  13. * $CKEditor = new CKEditor();
  14. * $CKEditor->editor("editor1", "<p>Initial value.</p>");
  15. * @endcode
  16. */
  17. class CKEditor
  18. {
  19. /**
  20. * The version of %CKEditor.
  21. * \private
  22. */
  23. var $version = '3.6.2';
  24. /**
  25. * A constant string unique for each release of %CKEditor.
  26. * \private
  27. */
  28. var $_timestamp = 'B8DJ5M3';
  29. /**
  30. * URL to the %CKEditor installation directory (absolute or relative to document root).
  31. * If not set, CKEditor will try to guess it's path.
  32. *
  33. * Example usage:
  34. * @code
  35. * $CKEditor->basePath = '/ckeditor/';
  36. * @endcode
  37. */
  38. var $basePath;
  39. /**
  40. * An array that holds the global %CKEditor configuration.
  41. * For the list of available options, see http://docs.cksource.com/ckeditor_api/symbols/CKEDITOR.config.html
  42. *
  43. * Example usage:
  44. * @code
  45. * $CKEditor->config['height'] = 400;
  46. * // Use @@ at the beggining of a string to ouput it without surrounding quotes.
  47. * $CKEditor->config['width'] = '@@screen.width * 0.8';
  48. * @endcode
  49. */
  50. var $config = array();
  51. /**
  52. * A boolean variable indicating whether CKEditor has been initialized.
  53. * Set it to true only if you have already included
  54. * &lt;script&gt; tag loading ckeditor.js in your website.
  55. */
  56. var $initialized = false;
  57. /**
  58. * Boolean variable indicating whether created code should be printed out or returned by a function.
  59. *
  60. * Example 1: get the code creating %CKEditor instance and print it on a page with the "echo" function.
  61. * @code
  62. * $CKEditor = new CKEditor();
  63. * $CKEditor->returnOutput = true;
  64. * $code = $CKEditor->editor("editor1", "<p>Initial value.</p>");
  65. * echo "<p>Editor 1:</p>";
  66. * echo $code;
  67. * @endcode
  68. */
  69. var $returnOutput = false;
  70. /**
  71. * An array with textarea attributes.
  72. *
  73. * When %CKEditor is created with the editor() method, a HTML &lt;textarea&gt; element is created,
  74. * it will be displayed to anyone with JavaScript disabled or with incompatible browser.
  75. */
  76. var $textareaAttributes = array( "rows" => 8, "cols" => 60 );
  77. /**
  78. * A string indicating the creation date of %CKEditor.
  79. * Do not change it unless you want to force browsers to not use previously cached version of %CKEditor.
  80. */
  81. var $timestamp = "B8DJ5M3";
  82. /**
  83. * An array that holds event listeners.
  84. * \private
  85. */
  86. var $_events = array();
  87. /**
  88. * An array that holds global event listeners.
  89. * \private
  90. */
  91. var $_globalEvents = array();
  92. /**
  93. * Main Constructor.
  94. *
  95. * @param $basePath (string) URL to the %CKEditor installation directory (optional).
  96. */
  97. function CKEditor($basePath = null) {
  98. if (!empty($basePath)) {
  99. $this->basePath = $basePath;
  100. }
  101. }
  102. /**
  103. * Creates a %CKEditor instance.
  104. * In incompatible browsers %CKEditor will downgrade to plain HTML &lt;textarea&gt; element.
  105. *
  106. * @param $name (string) Name of the %CKEditor instance (this will be also the "name" attribute of textarea element).
  107. * @param $value (string) Initial value (optional).
  108. * @param $config (array) The specific configurations to apply to this editor instance (optional).
  109. * @param $events (array) Event listeners for this editor instance (optional).
  110. *
  111. * Example usage:
  112. * @code
  113. * $CKEditor = new CKEditor();
  114. * $CKEditor->editor("field1", "<p>Initial value.</p>");
  115. * @endcode
  116. *
  117. * Advanced example:
  118. * @code
  119. * $CKEditor = new CKEditor();
  120. * $config = array();
  121. * $config['toolbar'] = array(
  122. * array( 'Source', '-', 'Bold', 'Italic', 'Underline', 'Strike' ),
  123. * array( 'Image', 'Link', 'Unlink', 'Anchor' )
  124. * );
  125. * $events['instanceReady'] = 'function (ev) {
  126. * alert("Loaded: " + ev.editor.name);
  127. * }';
  128. * $CKEditor->editor("field1", "<p>Initial value.</p>", $config, $events);
  129. * @endcode
  130. */
  131. function editor($name, $value = "", $config = array(), $events = array())
  132. {
  133. $attr = "";
  134. foreach ($this->textareaAttributes as $key => $val) {
  135. $attr.= " " . $key . '="' . str_replace('"', '&quot;', $val) . '"';
  136. }
  137. $out = "<textarea name=\"" . $name . "\"" . $attr . ">" . htmlspecialchars($value) . "</textarea>\n";
  138. if (!$this->initialized) {
  139. $out .= $this->init();
  140. }
  141. $_config = $this->configSettings($config, $events);
  142. $js = $this->returnGlobalEvents();
  143. if (!empty($_config))
  144. $js .= "CKEDITOR.replace('".$name."', ".$this->jsEncode($_config).");";
  145. else
  146. $js .= "CKEDITOR.replace('".$name."');";
  147. $out .= $this->script($js);
  148. if (!$this->returnOutput) {
  149. print $out;
  150. $out = "";
  151. }
  152. return $out;
  153. }
  154. /**
  155. * Replaces a &lt;textarea&gt; with a %CKEditor instance.
  156. *
  157. * @param $id (string) The id or name of textarea element.
  158. * @param $config (array) The specific configurations to apply to this editor instance (optional).
  159. * @param $events (array) Event listeners for this editor instance (optional).
  160. *
  161. * Example 1: adding %CKEditor to &lt;textarea name="article"&gt;&lt;/textarea&gt; element:
  162. * @code
  163. * $CKEditor = new CKEditor();
  164. * $CKEditor->replace("article");
  165. * @endcode
  166. */
  167. function replace($id, $config = array(), $events = array())
  168. {
  169. $out = "";
  170. if (!$this->initialized) {
  171. $out .= $this->init();
  172. }
  173. $_config = $this->configSettings($config, $events);
  174. $js = $this->returnGlobalEvents();
  175. if (!empty($_config)) {
  176. $js .= "CKEDITOR.replace('".$id."', ".$this->jsEncode($_config).");";
  177. }
  178. else {
  179. $js .= "CKEDITOR.replace('".$id."');";
  180. }
  181. $out .= $this->script($js);
  182. if (!$this->returnOutput) {
  183. print $out;
  184. $out = "";
  185. }
  186. return $out;
  187. }
  188. /**
  189. * Replace all &lt;textarea&gt; elements available in the document with editor instances.
  190. *
  191. * @param $className (string) If set, replace all textareas with class className in the page.
  192. *
  193. * Example 1: replace all &lt;textarea&gt; elements in the page.
  194. * @code
  195. * $CKEditor = new CKEditor();
  196. * $CKEditor->replaceAll();
  197. * @endcode
  198. *
  199. * Example 2: replace all &lt;textarea class="myClassName"&gt; elements in the page.
  200. * @code
  201. * $CKEditor = new CKEditor();
  202. * $CKEditor->replaceAll( 'myClassName' );
  203. * @endcode
  204. */
  205. function replaceAll($className = null)
  206. {
  207. $out = "";
  208. if (!$this->initialized) {
  209. $out .= $this->init();
  210. }
  211. $_config = $this->configSettings();
  212. $js = $this->returnGlobalEvents();
  213. if (empty($_config)) {
  214. if (empty($className)) {
  215. $js .= "CKEDITOR.replaceAll();";
  216. }
  217. else {
  218. $js .= "CKEDITOR.replaceAll('".$className."');";
  219. }
  220. }
  221. else {
  222. $classDetection = "";
  223. $js .= "CKEDITOR.replaceAll( function(textarea, config) {\n";
  224. if (!empty($className)) {
  225. $js .= " var classRegex = new RegExp('(?:^| )' + '". $className ."' + '(?:$| )');\n";
  226. $js .= " if (!classRegex.test(textarea.className))\n";
  227. $js .= " return false;\n";
  228. }
  229. $js .= " CKEDITOR.tools.extend(config, ". $this->jsEncode($_config) .", true);";
  230. $js .= "} );";
  231. }
  232. $out .= $this->script($js);
  233. if (!$this->returnOutput) {
  234. print $out;
  235. $out = "";
  236. }
  237. return $out;
  238. }
  239. /**
  240. * Adds event listener.
  241. * Events are fired by %CKEditor in various situations.
  242. *
  243. * @param $event (string) Event name.
  244. * @param $javascriptCode (string) Javascript anonymous function or function name.
  245. *
  246. * Example usage:
  247. * @code
  248. * $CKEditor->addEventHandler('instanceReady', 'function (ev) {
  249. * alert("Loaded: " + ev.editor.name);
  250. * }');
  251. * @endcode
  252. */
  253. function addEventHandler($event, $javascriptCode)
  254. {
  255. if (!isset($this->_events[$event])) {
  256. $this->_events[$event] = array();
  257. }
  258. // Avoid duplicates.
  259. if (!in_array($javascriptCode, $this->_events[$event])) {
  260. $this->_events[$event][] = $javascriptCode;
  261. }
  262. }
  263. /**
  264. * Clear registered event handlers.
  265. * Note: this function will have no effect on already created editor instances.
  266. *
  267. * @param $event (string) Event name, if not set all event handlers will be removed (optional).
  268. */
  269. function clearEventHandlers($event = null)
  270. {
  271. if (!empty($event)) {
  272. $this->_events[$event] = array();
  273. }
  274. else {
  275. $this->_events = array();
  276. }
  277. }
  278. /**
  279. * Adds global event listener.
  280. *
  281. * @param $event (string) Event name.
  282. * @param $javascriptCode (string) Javascript anonymous function or function name.
  283. *
  284. * Example usage:
  285. * @code
  286. * $CKEditor->addGlobalEventHandler('dialogDefinition', 'function (ev) {
  287. * alert("Loading dialog: " + ev.data.name);
  288. * }');
  289. * @endcode
  290. */
  291. function addGlobalEventHandler($event, $javascriptCode)
  292. {
  293. if (!isset($this->_globalEvents[$event])) {
  294. $this->_globalEvents[$event] = array();
  295. }
  296. // Avoid duplicates.
  297. if (!in_array($javascriptCode, $this->_globalEvents[$event])) {
  298. $this->_globalEvents[$event][] = $javascriptCode;
  299. }
  300. }
  301. /**
  302. * Clear registered global event handlers.
  303. * Note: this function will have no effect if the event handler has been already printed/returned.
  304. *
  305. * @param $event (string) Event name, if not set all event handlers will be removed (optional).
  306. */
  307. function clearGlobalEventHandlers($event = null)
  308. {
  309. if (!empty($event)) {
  310. $this->_globalEvents[$event] = array();
  311. }
  312. else {
  313. $this->_globalEvents = array();
  314. }
  315. }
  316. /**
  317. * Prints javascript code.
  318. * \private
  319. *
  320. * @param string $js
  321. */
  322. function script($js)
  323. {
  324. $out = "<script type=\"text/javascript\">";
  325. $out .= "//<![CDATA[\n";
  326. $out .= $js;
  327. $out .= "\n//]]>";
  328. $out .= "</script>\n";
  329. return $out;
  330. }
  331. /**
  332. * Returns the configuration array (global and instance specific settings are merged into one array).
  333. * \private
  334. *
  335. * @param $config (array) The specific configurations to apply to editor instance.
  336. * @param $events (array) Event listeners for editor instance.
  337. */
  338. function configSettings($config = array(), $events = array())
  339. {
  340. $_config = $this->config;
  341. $_events = $this->_events;
  342. if (is_array($config) && !empty($config)) {
  343. $_config = array_merge($_config, $config);
  344. }
  345. if (is_array($events) && !empty($events)) {
  346. foreach ($events as $eventName => $code) {
  347. if (!isset($_events[$eventName])) {
  348. $_events[$eventName] = array();
  349. }
  350. if (!in_array($code, $_events[$eventName])) {
  351. $_events[$eventName][] = $code;
  352. }
  353. }
  354. }
  355. if (!empty($_events)) {
  356. foreach($_events as $eventName => $handlers) {
  357. if (empty($handlers)) {
  358. continue;
  359. }
  360. else if (count($handlers) == 1) {
  361. $_config['on'][$eventName] = '@@'.$handlers[0];
  362. }
  363. else {
  364. $_config['on'][$eventName] = '@@function (ev){';
  365. foreach ($handlers as $handler => $code) {
  366. $_config['on'][$eventName] .= '('.$code.')(ev);';
  367. }
  368. $_config['on'][$eventName] .= '}';
  369. }
  370. }
  371. }
  372. return $_config;
  373. }
  374. /**
  375. * Return global event handlers.
  376. * \private
  377. */
  378. function returnGlobalEvents()
  379. {
  380. static $returnedEvents;
  381. $out = "";
  382. if (!isset($returnedEvents)) {
  383. $returnedEvents = array();
  384. }
  385. if (!empty($this->_globalEvents)) {
  386. foreach ($this->_globalEvents as $eventName => $handlers) {
  387. foreach ($handlers as $handler => $code) {
  388. if (!isset($returnedEvents[$eventName])) {
  389. $returnedEvents[$eventName] = array();
  390. }
  391. // Return only new events
  392. if (!in_array($code, $returnedEvents[$eventName])) {
  393. $out .= ($code ? "\n" : "") . "CKEDITOR.on('". $eventName ."', $code);";
  394. $returnedEvents[$eventName][] = $code;
  395. }
  396. }
  397. }
  398. }
  399. return $out;
  400. }
  401. /**
  402. * Initializes CKEditor (executed only once).
  403. * \private
  404. */
  405. function init()
  406. {
  407. static $initComplete;
  408. $out = "";
  409. if (!empty($initComplete)) {
  410. return "";
  411. }
  412. if ($this->initialized) {
  413. $initComplete = true;
  414. return "";
  415. }
  416. $args = "";
  417. $ckeditorPath = $this->ckeditorPath();
  418. if (!empty($this->timestamp) && $this->timestamp != "%"."TIMESTAMP%") {
  419. $args = '?t=' . $this->timestamp;
  420. }
  421. // Skip relative paths...
  422. if (strpos($ckeditorPath, '..') !== 0) {
  423. $out .= $this->script("window.CKEDITOR_BASEPATH='". $ckeditorPath ."';");
  424. }
  425. $out .= "<script type=\"text/javascript\" src=\"" . $ckeditorPath . 'ckeditor.js' . $args . "\"></script>\n";
  426. $extraCode = "";
  427. if ($this->timestamp != $this->_timestamp) {
  428. $extraCode .= ($extraCode ? "\n" : "") . "CKEDITOR.timestamp = '". $this->timestamp ."';";
  429. }
  430. if ($extraCode) {
  431. $out .= $this->script($extraCode);
  432. }
  433. $initComplete = $this->initialized = true;
  434. return $out;
  435. }
  436. /**
  437. * Return path to ckeditor.js.
  438. * \private
  439. */
  440. function ckeditorPath()
  441. {
  442. if (!empty($this->basePath)) {
  443. return $this->basePath;
  444. }
  445. /**
  446. * The absolute pathname of the currently executing script.
  447. * Note: If a script is executed with the CLI, as a relative path, such as file.php or ../file.php,
  448. * $_SERVER['SCRIPT_FILENAME'] will contain the relative path specified by the user.
  449. */
  450. if (isset($_SERVER['SCRIPT_FILENAME'])) {
  451. $realPath = dirname($_SERVER['SCRIPT_FILENAME']);
  452. }
  453. else {
  454. /**
  455. * realpath - Returns canonicalized absolute pathname
  456. */
  457. $realPath = realpath( './' ) ;
  458. }
  459. /**
  460. * The filename of the currently executing script, relative to the document root.
  461. * For instance, $_SERVER['PHP_SELF'] in a script at the address http://example.com/test.php/foo.bar
  462. * would be /test.php/foo.bar.
  463. */
  464. $selfPath = dirname($_SERVER['PHP_SELF']);
  465. $file = str_replace("\\", "/", __FILE__);
  466. if (!$selfPath || !$realPath || !$file) {
  467. return "/ckeditor/";
  468. }
  469. $documentRoot = substr($realPath, 0, strlen($realPath) - strlen($selfPath));
  470. $fileUrl = substr($file, strlen($documentRoot));
  471. $ckeditorUrl = str_replace("ckeditor_php4.php", "", $fileUrl);
  472. return $ckeditorUrl;
  473. }
  474. /**
  475. * This little function provides a basic JSON support.
  476. * \private
  477. *
  478. * @param mixed $val
  479. * @return string
  480. */
  481. function jsEncode($val)
  482. {
  483. if (is_null($val)) {
  484. return 'null';
  485. }
  486. if (is_bool($val)) {
  487. return $val ? 'true' : 'false';
  488. }
  489. if (is_int($val)) {
  490. return $val;
  491. }
  492. if (is_float($val)) {
  493. return str_replace(',', '.', $val);
  494. }
  495. if (is_array($val) || is_object($val)) {
  496. if (is_array($val) && (array_keys($val) === range(0,count($val)-1))) {
  497. return '[' . implode(',', array_map(array($this, 'jsEncode'), $val)) . ']';
  498. }
  499. $temp = array();
  500. foreach ($val as $k => $v){
  501. $temp[] = $this->jsEncode("{$k}") . ':' . $this->jsEncode($v);
  502. }
  503. return '{' . implode(',', $temp) . '}';
  504. }
  505. // String otherwise
  506. if (strpos($val, '@@') === 0)
  507. return substr($val, 2);
  508. if (strtoupper(substr($val, 0, 9)) == 'CKEDITOR.')
  509. return $val;
  510. return '"' . str_replace(array("\\", "/", "\n", "\t", "\r", "\x08", "\x0c", '"'), array('\\\\', '\\/', '\\n', '\\t', '\\r', '\\b', '\\f', '\"'), $val) . '"';
  511. }
  512. }