PageRenderTime 58ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/jFormer/jformer.php

https://bitbucket.org/izubizarreta/https-bitbucket.org-bityvip
PHP | 4168 lines | 2973 code | 625 blank | 570 comment | 670 complexity | 9ceca5f435dbf0586b5ea75a08240d39 MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.0, JSON, GPL-2.0, BSD-3-Clause, LGPL-2.1, MIT

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. class JFormElement {
  3. private $type;
  4. private $unaryTagArray = array('input', 'img', 'hr', 'br', 'meta', 'link');
  5. private $attributeArray;
  6. private $innerHtml;
  7. /**
  8. * Constructor
  9. *
  10. * @param <type> $type
  11. * @param <type> $attributeArray
  12. * @param <type> $unaryTagArray
  13. */
  14. public function __construct($type, $attributeArray = array()) {
  15. $this->type = strtolower($type);
  16. foreach ($attributeArray as $attribute => $value) {
  17. $this->setAttribute($attribute, $value);
  18. }
  19. return $this;
  20. }
  21. /**
  22. * Set an array, can pass an array or a key, value combination
  23. *
  24. * @param <type> $attribute
  25. * @param <type> $value
  26. */
  27. public function getAttribute($attribute) {
  28. return $this->attributeArray[$attribute];
  29. }
  30. function setAttribute($attribute, $value = '') {
  31. if (!is_array($attribute)) {
  32. $this->attributeArray[$attribute] = $value;
  33. } else {
  34. $this->attributeArray = array_merge($this->attributeArray, $attribute);
  35. }
  36. return $this;
  37. }
  38. function addToAttribute($attribute, $value = '') {
  39. if (isset($this->attributeArray[$attribute])) {
  40. $currentValue = $this->attributeArray[$attribute];
  41. } else {
  42. $currentValue = '';
  43. }
  44. $this->attributeArray[$attribute] = $currentValue . $value;
  45. return $this;
  46. }
  47. function addClassName($className) {
  48. $currentClasses = $this->getAttribute('class');
  49. // Check to see if the class is already added
  50. if (!strstr($currentClasses, $className)) {
  51. $newClasses = $currentClasses . ' ' . $className;
  52. $this->setAttribute('class', $newClasses);
  53. }
  54. }
  55. /**
  56. * Insert an element into the current element
  57. *
  58. * @param <type> $object
  59. */
  60. function insert($object) {
  61. if (@get_class($object) == __class__) {
  62. $this->innerHtml .= $object->build();
  63. } else {
  64. $this->innerHtml .= $object;
  65. }
  66. return $this;
  67. }
  68. /**
  69. * Set the innerHtml of an element
  70. *
  71. * @param <type> $object
  72. * @return <type>
  73. */
  74. function update($object) {
  75. $this->innerHtml = $object;
  76. return $this;
  77. }
  78. /**
  79. * Builds the element
  80. *
  81. * @return <type>
  82. */
  83. function build() {
  84. // Start the tag
  85. $element = '<' . $this->type;
  86. // Add attributes
  87. if (count($this->attributeArray)) {
  88. foreach ($this->attributeArray as $key => $value) {
  89. $element .= ' ' . $key . '="' . $value . '"';
  90. }
  91. }
  92. // Close the element
  93. if (!in_array($this->type, $this->unaryTagArray)) {
  94. $element.= '>' . $this->innerHtml . '</' . $this->type . '>';
  95. } else {
  96. $element.= ' />';
  97. }
  98. // Don't format the XML string, saves time
  99. //return $this->formatXmlString($element);
  100. return $element;
  101. }
  102. /**
  103. * Echoes out the element
  104. *
  105. * @return <type>
  106. */
  107. function __toString() {
  108. return $this->build();
  109. }
  110. }
  111. /**
  112. * A Form object
  113. */
  114. class JFormer {
  115. // General settings
  116. var $id;
  117. var $class = 'jFormer';
  118. var $action;
  119. var $style;
  120. var $jFormPageArray = array();
  121. var $jFormerId;
  122. var $onSubmitFunctionServerSide = 'onSubmit';
  123. var $disableAnalytics = false;
  124. var $setupPageScroller = true;
  125. var $data;
  126. // Title, description, and submission button
  127. var $title = '';
  128. var $titleClass = 'jFormerTitle';
  129. var $description = '';
  130. var $descriptionClass = 'jFormerDescription';
  131. var $submitButtonText = 'Submit';
  132. var $submitProcessingButtonText = 'Processing...';
  133. var $afterControl = '';
  134. // Form options
  135. var $alertsEnabled = true;
  136. var $clientSideValidation = true;
  137. var $debugMode = false;
  138. var $validationTips = true;
  139. // Page navigator
  140. var $pageNavigatorEnabled = false;
  141. var $pageNavigator = array();
  142. // Progress bar
  143. var $progressBar = false;
  144. // Splash page
  145. var $splashPageEnabled = false;
  146. var $splashPage = array();
  147. // Save state options
  148. var $saveStateEnabled = false;
  149. var $saveState = array();
  150. // Animations
  151. var $animationOptions = null;
  152. // Custom script execution before form submission
  153. var $onSubmitStartClientSide = '';
  154. var $onSubmitFinishClientSide = '';
  155. // Security options
  156. var $requireSsl = false; // Not implemented yet
  157. // Essential class variables
  158. var $status = array('status' => 'processing', 'response' => 'Form initialized.');
  159. // Validation
  160. var $jValidator;
  161. var $validationResponse = array();
  162. var $validationPassed = null;
  163. /**
  164. * Constructor
  165. */
  166. function __construct($id, $optionArray = array(), $jFormPageArray = array()) {
  167. // Set the id
  168. $this->id = $id;
  169. // Set the action dynamically
  170. $callingFile = debug_backtrace();
  171. $callingFile = $callingFile[0]['file'];
  172. $this->action = str_replace($_SERVER['DOCUMENT_ROOT'], '', $callingFile);
  173. // Use the options array to update the form variables
  174. if (is_array($optionArray)) {
  175. foreach ($optionArray as $option => $value) {
  176. $this->{$option} = $value;
  177. }
  178. }
  179. // Set defaults for the page navigator
  180. if (!empty($this->pageNavigator)) {
  181. $this->pageNavigatorEnabled = true;
  182. } else if ($this->pageNavigator == true) {
  183. $this->pageNavigator = array(
  184. 'position' => 'top'
  185. );
  186. }
  187. // Set defaults for the save state
  188. if (!empty($this->saveState)) {
  189. $this->saveStateEnabled = true;
  190. if (empty($this->saveState['showSavingAlert'])) {
  191. $this->saveState['showSavingAlert'] = true;
  192. }
  193. } else {
  194. $this->saveState = array(
  195. 'interval' => 30,
  196. 'showSavingAlert' => true,
  197. );
  198. }
  199. // Set defaults for the splash page
  200. if (!empty($this->splashPage)) {
  201. $this->splashPageEnabled = true;
  202. } else if ($this->saveStateEnabled == true) {
  203. $this->splashPage = array(
  204. 'content' => '',
  205. 'splashButtonText' => 'Begin'
  206. );
  207. }
  208. // Add the pages from the constructor
  209. foreach ($jFormPageArray as $jFormPage) {
  210. $this->addJFormPage($jFormPage);
  211. }
  212. return $this;
  213. }
  214. function addJFormPage($jFormPage) {
  215. $jFormPage->jFormer = $this;
  216. $this->jFormPageArray[$jFormPage->id] = $jFormPage;
  217. return $this;
  218. }
  219. function addJFormPages($jFormPages) {
  220. if (is_array($jFormPages)) {
  221. foreach ($jFormPages as $jFormPage) {
  222. $jFormPage->jFormer = $this;
  223. $this->jFormPageArray[$jFormPage->id] = $jFormPage;
  224. }
  225. }
  226. $jFormPage->jFormer = $this;
  227. $this->jFormPageArray[$jFormPage->id] = $jFormPage;
  228. return $this;
  229. }
  230. // Convenience method, no need to create a page or section to get components on the form
  231. function addJFormComponent($jFormComponent) {
  232. // Create an anonymous page if necessary
  233. if (empty($this->jFormPageArray)) {
  234. $this->addJFormPage(new JFormPage($this->id . '_page1', array('anonymous' => true)));
  235. }
  236. // Get the first page in the jFormPageArray
  237. $currentJFormPage = current($this->jFormPageArray);
  238. // Get the last section in the page
  239. $lastJFormSection = end($currentJFormPage->jFormSectionArray);
  240. // If the last section exists and is anonymous, add the component to it
  241. if (!empty($lastJFormSection) && $lastJFormSection->anonymous) {
  242. $lastJFormSection->addJFormComponent($jFormComponent);
  243. }
  244. // If the last section in the page does not exist or is not anonymous, add a new anonymous section and add the component to it
  245. else {
  246. // Create an anonymous section
  247. $anonymousSection = new JFormSection($currentJFormPage->id . '_section' . (sizeof($currentJFormPage->jFormSectionArray) + 1), array('anonymous' => true));
  248. // Add the anonymous section to the page
  249. $currentJFormPage->addJFormSection($anonymousSection->addJFormComponent($jFormComponent));
  250. }
  251. return $this;
  252. }
  253. function addJFormComponentArray($jFormComponentArray) {
  254. foreach ($jFormComponentArray as $jFormComponent) {
  255. $this->addJFormComponent($jFormComponent);
  256. }
  257. return $this;
  258. }
  259. // Convenience method, no need to create a to get a section on the form
  260. function addJFormSection($jFormSection) {
  261. // Create an anonymous page if necessary
  262. if (empty($this->jFormPageArray)) {
  263. $this->addJFormPage(new JFormPage($this->id . '_page1', array('anonymous' => true)));
  264. }
  265. // Get the first page in the jFormPageArray
  266. $currentJFormPage = current($this->jFormPageArray);
  267. // Add the section to the first page
  268. $currentJFormPage->addJFormSection($jFormSection);
  269. return $this;
  270. }
  271. function setStatus($status, $response) {
  272. $this->status = array('status' => $status, 'response' => $response);
  273. return $this->status;
  274. }
  275. function resetStatus() {
  276. $this->status = array('status' => 'processing', 'response' => 'Form status reset.');
  277. return $this->status;
  278. }
  279. function getStatus() {
  280. return $this->status;
  281. }
  282. function validate() {
  283. // Update the form status
  284. $this->setStatus('processing', 'Validating component values.');
  285. // Clear the validation response
  286. $this->validationResponse = array();
  287. // Validate each page
  288. foreach ($this->jFormPageArray as $jFormPage) {
  289. $this->validationResponse[$jFormPage->id] = $jFormPage->validate();
  290. }
  291. // Walk through all of the pages to see if there are any errors
  292. $this->validationPassed = true;
  293. foreach ($this->validationResponse as $jFormPageKey => $jFormPage) {
  294. foreach ($jFormPage as $jFormSectionKey => $jFormSection) {
  295. // If there are section instances
  296. if ($jFormSection != null && array_key_exists(0, $jFormSection) && is_array($jFormSection[0])) {
  297. foreach ($jFormSection as $jFormSectionInstanceIndex => $jFormSectionInstance) {
  298. foreach ($jFormSectionInstance as $jFormComponentKey => $jFormComponentErrorMessageArray) {
  299. // If there are component instances
  300. if ($jFormComponentErrorMessageArray != null && array_key_exists(0, $jFormComponentErrorMessageArray) && is_array($jFormComponentErrorMessageArray[0])) {
  301. foreach ($jFormComponentErrorMessageArray as $jFormComponentInstanceErrorMessageArray) {
  302. // If the first value is not empty, the component did not pass validation
  303. if (!empty($jFormComponentInstanceErrorMessageArray[0]) || sizeof($jFormComponentInstanceErrorMessageArray) > 1) {
  304. $this->validationPassed = false;
  305. }
  306. }
  307. } else {
  308. if (!empty($jFormComponentErrorMessageArray)) {
  309. $this->validationPassed = false;
  310. }
  311. }
  312. }
  313. }
  314. }
  315. // No section instances
  316. else {
  317. foreach ($jFormSection as $jFormComponentErrorMessageArray) {
  318. // Component instances
  319. if ($jFormComponentErrorMessageArray != null && array_key_exists(0, $jFormComponentErrorMessageArray) && is_array($jFormComponentErrorMessageArray[0])) {
  320. foreach ($jFormComponentErrorMessageArray as $jFormComponentInstanceErrorMessageArray) {
  321. // If the first value is not empty, the component did not pass validation
  322. if (!empty($jFormComponentInstanceErrorMessageArray[0]) || sizeof($jFormComponentInstanceErrorMessageArray) > 1) {
  323. $this->validationPassed = false;
  324. }
  325. }
  326. } else {
  327. if (!empty($jFormComponentErrorMessageArray)) {
  328. $this->validationPassed = false;
  329. }
  330. }
  331. }
  332. }
  333. }
  334. }
  335. // Update the form status
  336. $this->setStatus('processing', 'Validation complete.');
  337. return $this->validationResponse;
  338. }
  339. function getData() {
  340. $this->data = array();
  341. foreach ($this->jFormPageArray as $jFormPageKey => $jFormPage) {
  342. if (!$jFormPage->anonymous) {
  343. $this->data[$jFormPageKey] = $jFormPage->getData();
  344. } else {
  345. foreach ($jFormPage->jFormSectionArray as $jFormSectionKey => $jFormSection) {
  346. if (!$jFormSection->anonymous) {
  347. $this->data[$jFormSectionKey] = $jFormSection->getData();
  348. } else {
  349. foreach ($jFormSection->jFormComponentArray as $jFormComponentKey => $jFormComponent) {
  350. if (get_class($jFormComponent) != 'JFormComponentHtml') { // Don't include HTML components
  351. $this->data[$jFormComponentKey] = $jFormComponent->getValue();
  352. }
  353. }
  354. }
  355. }
  356. }
  357. }
  358. return json_decode(json_encode($this->data));
  359. }
  360. function setData($data, $fileArray = array()) {
  361. // Get the form data as an object, handle apache auto-add slashes on post requests
  362. $jFormerData = json_decode(urldecode($data));
  363. if (!is_object($jFormerData)) {
  364. $jFormerData = json_decode(urldecode(stripslashes($data)));
  365. }
  366. // Clear all of the component values
  367. $this->clearData();
  368. //print_r($jFormerData); exit();
  369. //print_r($fileArray);
  370. // Update the form status
  371. $this->setStatus('processing', 'Setting component values.');
  372. // Assign all of the received JSON values to the form
  373. foreach ($jFormerData as $jFormPageKey => $jFormPageData) {
  374. $this->jFormPageArray[$jFormPageKey]->setData($jFormPageData);
  375. }
  376. // Handle files
  377. if (!empty($fileArray)) {
  378. foreach ($fileArray as $jFormComponentId => $fileDataArray) {
  379. preg_match('/(-section([0-9])+)?(-instance([0-9])+)?:([A-Za-z0-9_-]+):([A-Za-z0-9_-]+)/', $jFormComponentId, $fileIdInfo);
  380. $jFormComponentId = str_replace($fileIdInfo[0], '', $jFormComponentId);
  381. $jFormPageId = $fileIdInfo[5];
  382. $jFormSectionId = $fileIdInfo[6];
  383. // Inside section instances
  384. if ($fileIdInfo[1] != null || ($fileIdInfo[1] == null && array_key_exists(0, $this->jFormPageArray[$jFormPageId]->jFormSectionArray[$jFormSectionId]->jFormComponentArray))) {
  385. // section instance
  386. // set the instance index
  387. if ($fileIdInfo[1] != null) {
  388. $jFormSectionInstanceIndex = $fileIdInfo[2] - 1;
  389. } else {
  390. // prime instance
  391. $jFormSectionInstanceIndex = 0;
  392. }
  393. // check to see if there is a component instance
  394. if ($fileIdInfo[3] != null || ($fileIdInfo[3] == null && is_array($this->jFormPageArray[$jFormPageId]->jFormSectionArray[$jFormSectionId]->jFormComponentArray[$jFormSectionInstanceIndex][$jFormComponentId]->value))) {
  395. // set the component instance index inside of a section instance
  396. if ($fileIdInfo[3] == null) {
  397. $jFormComponentInstanceIndex = 0;
  398. } else {
  399. $jFormComponentInstanceIndex = $fileIdInfo[4] - 1;
  400. }
  401. // set the value with a section and a component instance
  402. $this->jFormPageArray[$jFormPageId]->jFormSectionArray[$jFormSectionId]->jFormComponentArray[$jFormSectionInstanceIndex][$jFormComponentId]->value[$jFormComponentInstanceIndex] = $fileDataArray;
  403. } else {
  404. // set the value with a section instance
  405. $this->jFormPageArray[$jFormPageId]->jFormSectionArray[$jFormSectionId]->jFormComponentArray[$jFormSectionInstanceIndex][$jFormComponentId]->value = $fileDataArray;
  406. }
  407. }
  408. // Not section instances
  409. else {
  410. // has component instances
  411. if ($fileIdInfo[3] != null || ($fileIdInfo[3] == null && is_array($this->jFormPageArray[$jFormPageId]->jFormSectionArray[$jFormSectionId]->jFormComponentArray[$jFormComponentId]->value))) {
  412. // set component instance index
  413. if ($fileIdInfo[3] == null) {
  414. $jFormComponentInstanceIndex = 0;
  415. } else {
  416. $jFormComponentInstanceIndex = $fileIdInfo[4] - 1;
  417. }
  418. $this->jFormPageArray[$jFormPageId]->jFormSectionArray[$jFormSectionId]->jFormComponentArray[$jFormComponentId]->value[$jFormComponentInstanceIndex] = $fileDataArray;
  419. } else {
  420. // no instances
  421. $this->jFormPageArray[$jFormPageId]->jFormSectionArray[$jFormSectionId]->jFormComponentArray[$jFormComponentId]->value = $fileDataArray;
  422. }
  423. }
  424. }
  425. }
  426. return $this;
  427. }
  428. function clearData() {
  429. foreach ($this->jFormPageArray as $jFormPage) {
  430. $jFormPage->clearData();
  431. }
  432. $this->data = null;
  433. }
  434. function clearAllComponentValues() {
  435. // Clear all of the components in the form
  436. foreach ($this->jFormPageArray as $jFormPage) {
  437. foreach ($jFormPage->jFormSectionArray as $jFormSection) {
  438. foreach ($jFormSection->jFormComponentArray as $jFormComponent) {
  439. $jFormComponent->value = null;
  440. }
  441. }
  442. }
  443. }
  444. function selectJFormComponent($jFormComponentId) {
  445. foreach ($this->jFormPageArray as $jFormPageKey => $jFormPage) {
  446. foreach ($jFormPage->jFormSectionArray as $jFormSectionKey => $jFormSection) {
  447. foreach ($jFormSection->jFormComponentArray as $jFormComponentKey => $jFormComponent) {
  448. if ($jFormComponentId == $jFormComponentKey) {
  449. return $jFormComponent;
  450. }
  451. }
  452. }
  453. }
  454. return false;
  455. }
  456. public function initializeSaveState($username, $password, $formState, $formData) {
  457. // Make sure we have a table to work with
  458. $this->createSaveStateTable();
  459. $_SESSION[$this->id]['saveState']['username'] = $username;
  460. $_SESSION[$this->id]['saveState']['password'] = $password;
  461. // Either create a new form or resume an old one
  462. if ($formState == 'newForm') {
  463. // Check to see if the form state exists already
  464. $response = $this->getSavedState();
  465. if ($response['status'] == 'failure') {
  466. $response = $this->createSaveState($formData);
  467. } else {
  468. $response['status'] = 'exists';
  469. $response['response'] = array('failureNoticeHtml' => 'Form already exists. Either choose to resume the form, or enter a different password to create a new form.');
  470. }
  471. } else if ($formState == 'resumeForm') {
  472. $response = $this->getSavedState();
  473. }
  474. return $response;
  475. }
  476. public function createSaveState($formData) {
  477. // Make sure we have a table to work with
  478. $this->createSaveStateTable();
  479. // Connect to the database using the form settings
  480. $mysqli = new mysqli($this->saveState['database']['host'], $this->saveState['database']['username'], $this->saveState['database']['password'], $this->saveState['database']['database']);
  481. $sql = 'INSERT INTO `' . $this->saveState['database']['table'] . '` (`username`, `password`, `form`, `time_added`) VALUES (\'' . $_SESSION[$this->id]['saveState']['username'] . '\', MD5(\'' . $_SESSION[$this->id]['saveState']['password'] . '\'), \'' . $formData . '\', NOW())';
  482. $query = $mysqli->prepare($sql);
  483. if (is_object($query)) {
  484. $query->execute();
  485. } else {
  486. $debug = debug_backtrace();
  487. die("Error when preparing statement. Call came from {$debug[1]['function']} on line {$debug[1]['line']} in {$debug[1]['file']}.\n<br /><br />{$mysqli->error}:\n<br /><br />" . $sql);
  488. }
  489. if ($query->errno) {
  490. $response = array("status" => "failure", "response" => $query->error, "sql" => $sql);
  491. } else {
  492. // Send a save state link
  493. $this->sendSaveStateLink();
  494. $response = array('status' => 'success', "response" => 'Successfully created a new form state.');
  495. }
  496. return $response;
  497. }
  498. public function sendSaveStateLink() {
  499. // Short circuit if they don't have the e-mail options set
  500. if (!isset($this->saveState['email'])) {
  501. return false;
  502. }
  503. // Set the form headers
  504. $headers = 'From: ' . $this->saveState['email']['fromName'] . ' <' . $this->saveState['email']['fromEmail'] . '>' . "\r\n" . 'X-Mailer: PHP/' . phpversion();
  505. // Set the subject
  506. $subject = $this->saveState['email']['subject'];
  507. // Set the e-mail and replace [formUrl] with the real form URL
  508. $message = str_replace('[formUrl]', $this->saveState['email']['formUrl'], $this->saveState['email']['message']);
  509. // Send the message
  510. if (mail($_SESSION[$this->id]['saveState']['username'], $subject, $message, $headers)) {
  511. return true;
  512. } else {
  513. return false;
  514. }
  515. }
  516. public function saveState($formData) {
  517. // Make sure we have a table to work with
  518. $this->createSaveStateTable();
  519. // Connect to the database using the form settings
  520. $mysqli = new mysqli($this->saveState['database']['host'], $this->saveState['database']['username'], $this->saveState['database']['password'], $this->saveState['database']['database']);
  521. $sql = 'UPDATE `' . $this->saveState['database']['table'] . '` SET `form` = \'' . $formData . '\', `time_updated` = NOW() WHERE `username` = \'' . $_SESSION[$this->id]['saveState']['username'] . '\' AND `password` = MD5(\'' . $_SESSION[$this->id]['saveState']['password'] . '\')';
  522. $query = $mysqli->prepare($sql);
  523. if (is_object($query)) {
  524. $query->execute();
  525. } else {
  526. $debug = debug_backtrace();
  527. die("Error when preparing statement. Call came from {$debug[1]['function']} on line {$debug[1]['line']} in {$debug[1]['file']}.\n<br /><br />{$mysqli->error}:\n<br /><br />" . $sql);
  528. }
  529. if ($query->errno) {
  530. $response = array("status" => "failure", "response" => $query->error, "sql" => $sql);
  531. } else {
  532. $response = array('status' => 'success', "response" => 'Successfully updated the form state.');
  533. }
  534. return $response;
  535. }
  536. public function getSavedState() {
  537. // Connect to the database
  538. $mysqli = new mysqli($this->saveState['database']['host'], $this->saveState['database']['username'], $this->saveState['database']['password'], $this->saveState['database']['database']);
  539. // Get the saved state from the appropriate table
  540. $sql = 'SELECT * FROM `' . $this->saveState['database']['table'] . '` WHERE `username` = \'' . $_SESSION[$this->id]['saveState']['username'] . '\' AND `password` = MD5(\'' . $_SESSION[$this->id]['saveState']['password'] . '\')';
  541. $query = $mysqli->prepare($sql);
  542. if (is_object($query)) {
  543. $query->execute();
  544. } else {
  545. $debug = debug_backtrace();
  546. die("Error when preparing statement. Call came from {$debug[1]['function']} on line {$debug[1]['line']} in {$debug[1]['file']}.\n<br /><br />{$mysqli->error}:\n<br /><br />" . $sql);
  547. }
  548. $query->store_result();
  549. if ($query->errno) {
  550. $response = array("status" => "failure", "response" => $query->error, "sql" => $sql);
  551. } else if ($query->num_rows == 0) {
  552. $response = array("status" => "failure", "response" => array('failureNoticeHtml' => 'No form exists for that username and password combination. Try again or start a new form.'));
  553. } else {
  554. $resultArray = array();
  555. for ($i = 0; $i < $query->num_rows(); $i++) {
  556. $resultArray[$i] = array();
  557. $boundedVariables = array();
  558. $meta = $query->result_metadata();
  559. while ($column = $meta->fetch_field()) {
  560. $resultArray[$i][$column->name] = null;
  561. $boundedVariables[] = &$resultArray[$i][$column->name];
  562. }
  563. call_user_func_array(array($query, 'bind_result'), $boundedVariables);
  564. $query->fetch();
  565. }
  566. foreach ($resultArray as &$result) {
  567. foreach ($result as &$value) {
  568. if (Utility::isJson($value)) {
  569. $value = json_decode($value);
  570. } else if (Utility::isJson(urldecode($value))) {
  571. $value = json_decode(urldecode($value));
  572. }
  573. }
  574. $result = json_decode(json_encode($result));
  575. }
  576. //print_r($result);
  577. $response = array("status" => "success", "response" => $result->form);
  578. }
  579. return $response;
  580. }
  581. public function createSaveStateTable() {
  582. $mysqli = new mysqli($this->saveState['database']['host'], $this->saveState['database']['username'], $this->saveState['database']['password'], $this->saveState['database']['database']);
  583. $sql = '
  584. CREATE TABLE IF NOT EXISTS `' . $this->saveState['database']['table'] . '` (
  585. `id` int(11) NOT NULL AUTO_INCREMENT,
  586. `username` varchar(64) NOT NULL,
  587. `password` varchar(32) NOT NULL,
  588. `form` text,
  589. `time_updated` datetime,
  590. `time_added` datetime,
  591. PRIMARY KEY(`id`),
  592. INDEX `' . $this->saveState['database']['table'] . '_index`(`id`, `username`, `password`)
  593. )
  594. ENGINE=MYISAM
  595. ROW_FORMAT=default
  596. ';
  597. $query = $mysqli->prepare($sql);
  598. if (is_object($query)) {
  599. $query->execute();
  600. } else {
  601. $debug = debug_backtrace();
  602. die("Error when preparing statement. Call came from {$debug[1]['function']} on line {$debug[1]['line']} in {$debug[1]['file']}.\n<br /><br />{$mysqli->error}:\n<br /><br />" . $sql);
  603. }
  604. $query->store_result();
  605. if ($query->errno) {
  606. $response = array("status" => "failure", "response" => $query->error, "sql" => $sql);
  607. } else {
  608. $response = array("status" => "success", "response" => 'Table `' . $this->saveState['database']['table'] . '` created successfully.');
  609. }
  610. return $response;
  611. }
  612. function saveToSession($callbackFunctionName) {
  613. // Patch the callback function into $this
  614. $this->jFormerId = $this->id . uniqid();
  615. $_SESSION[$this->jFormerId] = $this;
  616. return $this;
  617. }
  618. function processRequest($silent = false) {
  619. // Are they trying to post a file that is too large?
  620. if (isset($_SERVER['CONTENT_LENGTH']) && empty($_POST)) {
  621. $this->setStatus('success', array('failureNoticeHtml' => 'Your request (' . round($_SERVER['CONTENT_LENGTH'] / 1024 / 1024, 1) . 'M) was too large for the server to handle. ' . ini_get('post_max_size') . ' is the maximum request size.'));
  622. echo '
  623. <script type="text/javascript" language="javascript">
  624. parent.' . $this->id . 'Object.handleFormSubmissionResponse(' . json_encode($this->getStatus()) . ');
  625. </script>
  626. ';
  627. exit();
  628. }
  629. // Are they trying to post something to the form?
  630. if (isset($_POST['jFormer']) && $this->id == $_POST['jFormerId'] || isset($_POST['jFormerTask'])) {
  631. // Process the form, get the form state, or display the form
  632. if (isset($_POST['jFormer'])) {
  633. //echo json_encode($_POST);
  634. $onSubmitErrorMessageArray = array();
  635. // Set the form components and validate the form
  636. $this->setData($_POST['jFormer'], $_FILES);
  637. //print_r($this->getData());
  638. // Run validation
  639. $this->validate();
  640. if (!$this->validationPassed) {
  641. $this->setStatus('failure', array('validationFailed' => $this->validationResponse));
  642. } else {
  643. try {
  644. $onSubmitResponse = call_user_func($this->onSubmitFunctionServerSide, $this->getData());
  645. } catch (Exception $exception) {
  646. $onSubmitErrorMessageArray[] = $exception->getTraceAsString();
  647. }
  648. // Make sure you actually get a callback response
  649. if (empty($onSubmitResponse)) {
  650. $onSubmitErrorMessageArray[] = '<p>The function <b>' . $this->onSubmitFunctionServerSide . '</b> did not return a valid response.</p>';
  651. }
  652. // If there are no errors, it is a successful response
  653. if (empty($onSubmitErrorMessageArray)) {
  654. $this->setStatus('success', $onSubmitResponse);
  655. } else {
  656. $this->setStatus('failure', array('failureHtml' => $onSubmitErrorMessageArray));
  657. }
  658. }
  659. echo '
  660. <script type="text/javascript" language="javascript">
  661. parent.' . $this->id . 'Object.handleFormSubmissionResponse(' . json_encode($this->getStatus()) . ');
  662. </script>
  663. ';
  664. //echo json_encode($this->getValues());
  665. exit();
  666. }
  667. // Get the form's status
  668. else if (isset($_POST['jFormerTask']) && $_POST['jFormerTask'] == 'getFormStatus') {
  669. $onSubmitResponse = $this->getStatus();
  670. echo json_encode($onSubmitResponse);
  671. $this->resetStatus();
  672. exit();
  673. }
  674. // Set the save state username and password
  675. else if (isset($_POST['jFormerTask']) && $_POST['jFormerTask'] == 'initializeSaveState') {
  676. echo json_encode($this->initializeSaveState($_POST['identifier'], $_POST['password'], $_POST['formState'], $_POST['formData']));
  677. exit();
  678. }
  679. // Get the saved state
  680. else if (isset($_POST['jFormerTask']) && $_POST['jFormerTask'] == 'getSavedState') {
  681. echo json_encode($this->getSavedState($this->saveState['identifier'], $this->saveState['password']));
  682. exit();
  683. }
  684. // Save the current form state
  685. else if (isset($_POST['jFormerTask']) && $_POST['jFormerTask'] == 'saveState') {
  686. echo json_encode($this->saveState($_POST['formData']));
  687. exit();
  688. }
  689. }
  690. // If they aren't trying to post something to the form
  691. else if (!$silent) {
  692. $this->outputHtml();
  693. }
  694. }
  695. function getOptions() {
  696. $options = array();
  697. $options['options'] = array();
  698. $options['jFormPages'] = array();
  699. // Get all of the pages
  700. foreach ($this->jFormPageArray as $jFormPage) {
  701. $options['jFormPages'][$jFormPage->id] = $jFormPage->getOptions();
  702. }
  703. // Set form options
  704. if (!$this->clientSideValidation) {
  705. $options['options']['clientSideValidation'] = $this->clientSideValidation;
  706. }
  707. if ($this->debugMode) {
  708. $options['options']['debugMode'] = $this->debugMode;
  709. }
  710. if (!$this->validationTips) {
  711. $options['options']['validationTips'] = $this->validationTips;
  712. }
  713. if ($this->disableAnalytics) {
  714. $options['options']['disableAnalytics'] = $this->disableAnalytics;
  715. }
  716. if (!$this->setupPageScroller) {
  717. $options['options']['setupPageScroller'] = $this->setupPageScroller;
  718. }
  719. if ($this->animationOptions !== null) {
  720. $options['options']['animationOptions'] = $this->animationOptions;
  721. }
  722. if ($this->pageNavigatorEnabled) {
  723. $options['options']['pageNavigator'] = $this->pageNavigator;
  724. }
  725. if ($this->saveStateEnabled) {
  726. $options['options']['saveState'] = $this->saveState;
  727. // Don't give your database login out in the options
  728. unset($options['options']['saveState']['database']);
  729. }
  730. if ($this->splashPageEnabled) {
  731. $options['options']['splashPage'] = $this->splashPage;
  732. unset($options['options']['splashPage']['content']);
  733. }
  734. if (!empty($this->onSubmitStartClientSide)) {
  735. $options['options']['onSubmitStart'] = $this->onSubmitStartClientSide;
  736. }
  737. if (!empty($this->onSubmitFinishClientSide)) {
  738. $options['options']['onSubmitFinish'] = $this->onSubmitFinishClientSide;
  739. }
  740. if (!$this->alertsEnabled) {
  741. $options['options']['alertsEnabled'] = false;
  742. }
  743. if ($this->submitButtonText != 'Submit') {
  744. $options['options']['submitButtonText'] = $this->submitButtonText;
  745. }
  746. if ($this->submitProcessingButtonText != 'Processing...') {
  747. $options['options']['submitProcessingButtonText'] = $this->submitProcessingButtonText;
  748. }
  749. if ($this->progressBar) {
  750. $options['options']['progressBar'] = $this->progressBar;
  751. }
  752. if (empty($options['options'])) {
  753. unset($options['options']);
  754. }
  755. return $options;
  756. }
  757. function outputHtml() {
  758. echo $this->getHtml();
  759. }
  760. function __toString() {
  761. $element = $this->getHtml();
  762. return $element->__toString();
  763. }
  764. function getHtml() {
  765. // Create the form
  766. $formElement = new JFormElement('form', array(
  767. 'id' => $this->id,
  768. 'target' => $this->id . '-iframe',
  769. 'enctype' => 'multipart/form-data',
  770. 'method' => 'post',
  771. 'class' => $this->class,
  772. 'action' => $this->action,
  773. ));
  774. // Set the style
  775. if (!empty($this->style)) {
  776. $formElement->addToAttribute('style', $this->style);
  777. }
  778. // Global messages
  779. if ($this->alertsEnabled) {
  780. $jFormerAlertWrapperDiv = new JFormElement('div', array(
  781. 'class' => 'jFormerAlertWrapper',
  782. 'style' => 'display: none;',
  783. ));
  784. $alertDiv = new JFormElement('div', array(
  785. 'class' => 'jFormerAlert',
  786. ));
  787. $jFormerAlertWrapperDiv->insert($alertDiv);
  788. $formElement->insert($jFormerAlertWrapperDiv);
  789. }
  790. // If a splash is enabled
  791. if ($this->splashPageEnabled || $this->saveStateEnabled) {
  792. // Create a splash page div
  793. $splashPageDiv = new JFormElement('div', array(
  794. 'id' => $this->id . '-splash-page',
  795. 'class' => 'jFormerSplashPage jFormPage',
  796. ));
  797. // Set defaults if they aren't set
  798. if (!isset($this->splashPage['content'])) {
  799. $this->splashPage['content'] = '';
  800. }
  801. if (!isset($this->splashPage['splashButtonText'])) {
  802. $this->splashPage['splashButtonText'] = 'Begin';
  803. }
  804. $splashPageDiv->insert('<div class="jFormerSplashPageContent">' . $this->splashPage['content'] . '</div>');
  805. // If the form can be saved, show the necessary components
  806. if ($this->saveStateEnabled) {
  807. $saveStateIdentifier = new jFormComponentSingleLineText('saveStateIdentifier', 'E-mail address:', array(
  808. 'tip' => '<p>We will send form results to this e-mail address.</p>',
  809. 'validationOptions' => array('required', 'email'),
  810. ));
  811. $saveStateStatus = new jFormComponentMultipleChoice('saveStateStatus', 'Starting a new form?',
  812. array(
  813. array('value' => 'newForm', 'label' => 'Yes, let me start a new form', 'checked' => true),
  814. array('value' => 'resumeForm', 'label' => 'No, I want to continue a previous form'),
  815. ),
  816. array(
  817. 'multipleChoiceType' => 'radio',
  818. 'validationOptions' => array('required'),
  819. )
  820. );
  821. $saveStatePassword = new jFormComponentSingleLineText('saveStatePassword', 'Create password:', array(
  822. 'type' => 'password',
  823. 'tip' => '<p>Use this to come back and resume your form.</p>',
  824. 'showPasswordStrength' => true,
  825. 'validationOptions' => array('required', 'password'),
  826. ));
  827. // Add the components to the class save state variable
  828. $this->saveState['components'] = array($saveStateIdentifier->id => $saveStateIdentifier->getOptions(), $saveStateStatus->id => $saveStateStatus->getOptions(), $saveStatePassword->id => $saveStatePassword->getOptions());
  829. $splashPageDiv->insert($saveStateIdentifier->__toString() . $saveStateStatus->__toString() . $saveStatePassword->__toString());
  830. }
  831. // Create a splash button if there is no custom button ID
  832. if (!isset($this->splashPage['customButtonId'])) {
  833. $splashLi = new JFormElement('li', array('class' => 'splashLi'));
  834. $splashButton = new JFormElement('button', array('class' => 'splashButton'));
  835. $splashButton->update($this->splashPage['splashButtonText']);
  836. $splashLi->insert($splashButton);
  837. }
  838. }
  839. // Add a title to the form
  840. if (!empty($this->title)) {
  841. $title = new JFormElement('div', array(
  842. 'class' => $this->titleClass
  843. ));
  844. $title->update($this->title);
  845. $formElement->insert($title);
  846. }
  847. // Add a description to the form
  848. if (!empty($this->description)) {
  849. $description = new JFormElement('div', array(
  850. 'class' => $this->descriptionClass
  851. ));
  852. $description->update($this->description);
  853. $formElement->insert($description);
  854. }
  855. // Add the page navigator if enabled
  856. if ($this->pageNavigatorEnabled) {
  857. $pageNavigatorDiv = new JFormElement('div', array(
  858. 'class' => 'jFormPageNavigator',
  859. ));
  860. if (isset($this->pageNavigator['position']) && $this->pageNavigator['position'] == 'right') {
  861. $pageNavigatorDiv->addToAttribute('class', ' jFormPageNavigatorRight');
  862. } else {
  863. $pageNavigatorDiv->addToAttribute('class', ' jFormPageNavigatorTop');
  864. }
  865. $pageNavigatorUl = new JFormElement('ul', array(
  866. ));
  867. $jFormPageArrayCount = 0;
  868. foreach ($this->jFormPageArray as $jFormPageKey => $jFormPage) {
  869. $jFormPageArrayCount++;
  870. $pageNavigatorLabel = new JFormElement('li', array(
  871. 'id' => 'navigatePage' . $jFormPageArrayCount,
  872. 'class' => 'jFormPageNavigatorLink',
  873. ));
  874. // If the label is numeric
  875. if (isset($this->pageNavigator['label']) && $this->pageNavigator['label'] == 'numeric') {
  876. $pageNavigatorLabelText = 'Page ' . $jFormPageArrayCount;
  877. } else {
  878. // Add a link prefix if there is a title
  879. if (!empty($jFormPage->title)) {
  880. $pageNavigatorLabelText = '<span class="jFormNavigatorLinkPrefix">' . $jFormPageArrayCount . '</span> ' . strip_tags($jFormPage->title);
  881. } else {
  882. $pageNavigatorLabelText = 'Page ' . $jFormPageArrayCount;
  883. }
  884. }
  885. $pageNavigatorLabel->update($pageNavigatorLabelText);
  886. if ($jFormPageArrayCount != 1) {
  887. $pageNavigatorLabel->addToAttribute('class', ' jFormPageNavigatorLinkLocked');
  888. } else {
  889. $pageNavigatorLabel->addToAttribute('class', ' jFormPageNavigatorLinkUnlocked jFormPageNavigatorLinkActive');
  890. }
  891. $pageNavigatorUl->insert($pageNavigatorLabel);
  892. }
  893. // Add the page navigator ul to the div
  894. $pageNavigatorDiv->insert($pageNavigatorUl);
  895. // Add the progress bar if it is enabled
  896. if ($this->progressBar) {
  897. $pageNavigatorDiv->insert('<div class="jFormerProgress"><div class="jFormerProgressBar"></div></div>');
  898. }
  899. // Hide the progress bar if there is a splash page
  900. if ($this->splashPageEnabled) {
  901. $pageNavigatorDiv->addToAttribute('style', 'display: none;');
  902. }
  903. $formElement->insert($pageNavigatorDiv);
  904. }
  905. // Add the jFormerControl UL
  906. $jFormerControlUl = new JFormElement('ul', array(
  907. 'class' => 'jFormerControl',
  908. ));
  909. // Create the previous button
  910. $previousButtonLi = new JFormElement('li', array('class' => 'previousLi', 'style' => 'display: none;'));
  911. $previousButton = new JFormElement('button', array('class' => 'previousButton'));
  912. $previousButton->update('Previous');
  913. $previousButtonLi->insert($previousButton);
  914. // Create the next button
  915. $nextButtonLi = new JFormElement('li', array('class' => 'nextLi'));
  916. $nextButton = new JFormElement('button', array('class' => 'nextButton'));
  917. $nextButton->update($this->submitButtonText);
  918. // Don't show the next button
  919. if ($this->splashPageEnabled || $this->saveStateEnabled) {
  920. $nextButtonLi->setAttribute('style', 'display: none;');
  921. }
  922. $nextButtonLi->insert($nextButton);
  923. // Add a splash page button if it exists
  924. if (isset($splashLi)) {
  925. $jFormerControlUl->insert($splashLi);
  926. }
  927. // Add the previous and next buttons
  928. $jFormerControlUl->insert($previousButtonLi . $nextButtonLi);
  929. // Create the page wrapper and scrollers
  930. $jFormPageWrapper = new JFormElement('div', array('class' => 'jFormPageWrapper'));
  931. $jFormPageScroller = new JFormElement('div', array('class' => 'jFormPageScroller'));
  932. // Add a splash page if it exists
  933. if (isset($splashPageDiv)) {
  934. $jFormPageScroller->insert($splashPageDiv);
  935. }
  936. // Add the form pages to the form
  937. $jFormPageCount = 0;
  938. foreach ($this->jFormPageArray as $jFormPage) {
  939. // Hide everything but the first page
  940. if ($jFormPageCount != 0 || ($jFormPageCount == 0 && ($this->splashPageEnabled || $this->saveStateEnabled))) {
  941. $jFormPage->style .= 'display: none;';
  942. }
  943. $jFormPageScroller->insert($jFormPage);
  944. $jFormPageCount++;
  945. }
  946. // Page wrapper wrapper
  947. $pageWrapperContainer = new JFormElement('div', array('class' => 'jFormWrapperContainer'));
  948. // Insert the page wrapper and the jFormerControl UL to the form
  949. $formElement->insert($pageWrapperContainer->insert($jFormPageWrapper->insert($jFormPageScroller) . $jFormerControlUl));
  950. // Create a script tag to initialize jFormer JavaScript
  951. $script = new JFormElement('script', array(
  952. 'type' => 'text/javascript',
  953. 'language' => 'javascript'
  954. ));
  955. // Update the script tag
  956. $script->update('$(document).ready(function () { ' . $this->id . 'Object = new JFormer(\'' . $this->id . '\', ' . json_encode($this->getOptions()) . '); });');
  957. $formElement->insert($script);
  958. // Add a hidden iframe to handle the form posts
  959. $iframe = new JFormElement('iframe', array(
  960. 'id' => $this->id . '-iframe',
  961. 'name' => $this->id . '-iframe',
  962. 'class' => 'jFormerIFrame',
  963. 'frameborder' => 0,
  964. 'src' => '/empty.html',
  965. //'src' => str_replace($_SERVER['DOCUMENT_ROOT'], '', __FILE__).'?iframe=true',
  966. ));
  967. if ($this->debugMode) {
  968. $iframe->addToAttribute('style', 'display:block;');
  969. }
  970. $formElement->insert($iframe);
  971. // After control
  972. if (!empty($this->afterControl)) {
  973. $subSubmitInstructions = new JFormElement('div', array('class' => 'jFormerAfterControl'));
  974. $subSubmitInstructions->update($this->afterControl);
  975. $formElement->insert($subSubmitInstructions);
  976. }
  977. return $formElement;
  978. }
  979. static function formValuesToHtml($formValues) {
  980. $div = new JFormElement('div', array(
  981. 'style' => 'font-family: Arial, san-serif;'
  982. ));
  983. foreach ($formValues as $pageKey => $section) {
  984. $div->insert('<h1>' . Utility::stringToTitle(Utility::fromCamelCaseToSpaces($pageKey)) . '</h1>');
  985. foreach ($section as $sectionKey => $sectionValue) {
  986. // If the sectionValue is an array (instances)
  987. if (is_array($sectionValue)) {
  988. $div->insert('<h2>' . Utility::stringToTitle(Utility::fromCamelCaseToSpaces($sectionKey)) . ' (' . sizeof($sectionValue) . ' total)</h2>');
  989. foreach ($sectionValue as $sectionInstanceIndex => $section) {
  990. $div->insert('<h2>(' . ($sectionInstanceIndex + 1) . ') ' . Utility::stringToTitle(Utility::fromCamelCaseToSpaces($sectionKey)) . '</h2>');
  991. $div->insert(JFormer::sectionFormValuesToHtml($section));
  992. }
  993. } else {
  994. $div->insert('<h2>' . Utility::stringToTitle(Utility::fromCamelCaseToSpaces($sectionKey)) . '</h2>');
  995. $div->insert(JFormer::sectionFormValuesToHtml($sectionValue));
  996. }
  997. }
  998. }
  999. return $div;
  1000. }
  1001. static function sectionFormValuesToHtml($sectionFormValues) {
  1002. $div = new JFormElement('div');
  1003. foreach ($sectionFormValues as $componentKey => $componentValue) {
  1004. if (is_object($componentValue) || is_array($componentValue)) {
  1005. // If the component value is an array (instances)
  1006. if (is_array($componentValue)) {
  1007. $div->insert('<h4>' . Utility::stringToTitle(Utility::fromCamelCaseToSpaces($componentKey)) . ' (' . sizeof($componentValue) . ' total)</h4>');
  1008. } else {
  1009. $div->insert('<h4>' . Utility::stringToTitle(Utility::fromCamelCaseToSpaces($componentKey)) . '</h4>');
  1010. }
  1011. foreach ($componentValue as $componentValueKey => $componentValueValue) {
  1012. if (is_int($componentValueKey)) {
  1013. if (is_object($componentValueValue)) {
  1014. foreach ($componentValueValue as $instanceKey => $instanceValue) {
  1015. $div->insert('<p>(' . ($componentValueKey + 1) . ') ' . Utility::stringToTitle(Utility::fromCamelCaseToSpaces($instanceKey)) . ': <b>' . $instanceValue . '</b></p>');
  1016. }
  1017. } else {
  1018. $div->insert('<p><b>' . $componentValueValue . '</b></p>');
  1019. }
  1020. } else {
  1021. $div->insert('<p>' . Utility::stringToTitle(Utility::fromCamelCaseToSpaces($compo

Large files files are truncated, but you can click here to view the full file