PageRenderTime 40ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/manage/expressionengine/third_party/freeform/mod.freeform.php

https://bitbucket.org/jondaiello/h5sp-r
PHP | 4705 lines | 2723 code | 857 blank | 1125 comment | 347 complexity | 6423456dbd1584effeec738124ef821f MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception
  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * Freeform - User Side
  4. *
  5. * @package Solspace:Freeform
  6. * @author Solspace, Inc.
  7. * @copyright Copyright (c) 2008-2015, Solspace, Inc.
  8. * @link http://solspace.com/docs/freeform
  9. * @license http://www.solspace.com/license_agreement
  10. * @version 4.2.3
  11. * @filesource freeform/mod.freeform.php
  12. */
  13. if ( ! class_exists('Module_builder_freeform'))
  14. {
  15. require_once 'addon_builder/module_builder.php';
  16. }
  17. class Freeform extends Module_builder_freeform
  18. {
  19. /**
  20. * return data for when the constructor os only called
  21. * unused thusfar in this addon.
  22. * @var string
  23. */
  24. public $return_data = '';
  25. /**
  26. * Multipart form?
  27. * @var boolean
  28. * @see form
  29. */
  30. public $multipart = FALSE;
  31. /**
  32. * Params array storage for param
  33. * @var array
  34. * @see param
  35. */
  36. public $params = array();
  37. /**
  38. * params id for param fetch
  39. * @var integer
  40. * @see form
  41. * @see insert_params
  42. */
  43. public $params_id = 0;
  44. /**
  45. * Form ID storage
  46. * @var integer
  47. * @see form_id
  48. */
  49. public $form_id = 0;
  50. /**
  51. * Test Mode?
  52. *
  53. * @var boolean
  54. * @see do_exist
  55. */
  56. public $test_mode = FALSE;
  57. /**
  58. * Default Multipage Marker
  59. *
  60. * @var string
  61. * @see form
  62. * @see set_form_params
  63. */
  64. public $default_mp_page_marker = 'page';
  65. /**
  66. * Multipage Page Array
  67. *
  68. * @var array
  69. * @see get_mp_page_array
  70. */
  71. public $mp_page_array;
  72. /**
  73. * Prevents rerunning of set_form_params
  74. * @var boolean
  75. * @see set_form_params
  76. */
  77. public $params_ran = FALSE;
  78. /**
  79. * Form Data
  80. * @var array
  81. */
  82. public $form_data;
  83. /**
  84. * Params With Defaults
  85. * @var array
  86. * @see get_default_params
  87. */
  88. public $params_with_defaults;
  89. // --------------------------------------------------------------------
  90. /**
  91. * Constructor
  92. *
  93. * @access public
  94. * @return null
  95. */
  96. public function __construct ()
  97. {
  98. parent::__construct();
  99. // -------------------------------------
  100. // Module Installed and Up to Date?
  101. // -------------------------------------
  102. ee()->load->helper(array('text', 'form', 'url', 'string'));
  103. //avoids AR collisions
  104. $this->data->get_module_preferences();
  105. $this->data->get_global_module_preferences();
  106. $this->data->show_all_sites();
  107. }
  108. // END __construct()
  109. // --------------------------------------------------------------------
  110. /**
  111. * Form Info
  112. *
  113. * @access public
  114. * @return string parsed tagdata
  115. */
  116. public function form_info()
  117. {
  118. $form_ids = $this->form_id(TRUE, FALSE);
  119. ee()->load->model('freeform_form_model');
  120. if ($form_ids)
  121. {
  122. ee()->freeform_form_model->where_in('form_id', $form_ids);
  123. }
  124. // -------------------------------------
  125. // site ids
  126. // -------------------------------------
  127. //if its star, allow all
  128. if (ee()->TMPL->fetch_param('site_id') !== '*')
  129. {
  130. $site_id = $this->parse_numeric_array_param('site_id');
  131. //if this isn't false, its single or an array
  132. if ($site_id !== FALSE)
  133. {
  134. //no ids? exit
  135. if (empty($site_id['ids']))
  136. {
  137. ee()->freeform_form_model->reset();
  138. return $this->no_results_error();
  139. }
  140. //e.g. site_id="not 1"
  141. else if ($site_id['not'])
  142. {
  143. ee()->freeform_form_model->where_not_in(
  144. 'site_id',
  145. $site_id['ids']
  146. );
  147. }
  148. else
  149. {
  150. ee()->freeform_form_model->where_in(
  151. 'site_id',
  152. $site_id['ids']
  153. );
  154. }
  155. }
  156. //default
  157. else
  158. {
  159. ee()->freeform_form_model->where(
  160. 'site_id',
  161. ee()->config->item('site_id')
  162. );
  163. }
  164. }
  165. // -------------------------------------
  166. // form data
  167. // -------------------------------------
  168. $form_data = ee()->freeform_form_model
  169. ->select(
  170. 'form_id, site_id, ' .
  171. 'form_name, form_label, ' .
  172. 'form_description, author_id, ' .
  173. 'entry_date, edit_date'
  174. )
  175. ->order_by('form_id', 'asc')
  176. ->get();
  177. if ( ! $form_data)
  178. {
  179. return $this->no_results_error(($form_ids) ?
  180. 'invalid_form_id' :
  181. NULL
  182. );
  183. }
  184. // -------------------------------------
  185. // author data
  186. // -------------------------------------
  187. $author_ids = array();
  188. $author_data = array();
  189. foreach ($form_data as $row)
  190. {
  191. $author_ids[] = $row['author_id'];
  192. }
  193. $a_query = ee()->db->select('member_id, username, screen_name')
  194. ->from('members')
  195. ->where_in('member_id', array_unique($author_ids))
  196. ->get();
  197. if ($a_query->num_rows() > 0)
  198. {
  199. $author_data = $this->prepare_keyed_result(
  200. $a_query,
  201. 'member_id'
  202. );
  203. }
  204. // -------------------------------------
  205. // output
  206. // -------------------------------------
  207. $variables = array();
  208. ee()->load->model('freeform_entry_model');
  209. foreach ($form_data as $row)
  210. {
  211. $new_row = array();
  212. //prefix everything
  213. foreach ($row as $key => $value)
  214. {
  215. $new_row['freeform:' . $key] = $value;
  216. }
  217. //we are only counting completed entries
  218. $new_row['freeform:total_entries'] = ee()->freeform_entry_model
  219. ->id($row['form_id'])
  220. ->where('complete', 'y')
  221. ->count();
  222. $new_row['freeform:author'] = (
  223. isset($author_data[$row['author_id']]) ?
  224. (
  225. isset($author_data[$row['author_id']]['screen_name']) ?
  226. $author_data[$row['author_id']]['screen_name'] :
  227. $author_data[$row['author_id']]['username']
  228. ) :
  229. lang('n_a')
  230. );
  231. $variables[] = $new_row;
  232. }
  233. $prefixed_tags = array(
  234. 'count',
  235. 'switch',
  236. 'total_results'
  237. );
  238. $tagdata = ee()->TMPL->tagdata;
  239. $tagdata = $this->tag_prefix_replace(
  240. 'freeform:',
  241. $prefixed_tags,
  242. $tagdata
  243. );
  244. //this should handle backspacing as well
  245. $tagdata = ee()->TMPL->parse_variables($tagdata, $variables);
  246. $tagdata = $this->tag_prefix_replace(
  247. 'freeform:',
  248. $prefixed_tags,
  249. $tagdata,
  250. TRUE
  251. );
  252. return $tagdata;
  253. }
  254. //END form_info
  255. // --------------------------------------------------------------------
  256. /**
  257. * Freeform:Entries
  258. * {exp:freeform:entries}
  259. *
  260. * @access public
  261. * @return string tagdata
  262. */
  263. public function entries()
  264. {
  265. // -------------------------------------
  266. // form id
  267. // -------------------------------------
  268. $form_ids = $this->form_id(TRUE, FALSE);
  269. if ( ! $form_ids)
  270. {
  271. return $this->no_results_error('invalid_form_id');
  272. }
  273. if ( ! is_array($form_ids))
  274. {
  275. $form_ids = array($form_ids);
  276. }
  277. // -------------------------------------
  278. // libs, models, helper
  279. // -------------------------------------
  280. ee()->load->model('freeform_form_model');
  281. ee()->load->model('freeform_entry_model');
  282. ee()->load->model('freeform_field_model');
  283. ee()->load->model('freeform_file_upload_model');
  284. ee()->load->library('freeform_forms');
  285. ee()->load->library('freeform_fields');
  286. // -------------------------------------
  287. // start cache for count and result
  288. // -------------------------------------
  289. $forms_data = ee()->freeform_form_model
  290. ->key('form_id')
  291. ->get(array('form_id' => $form_ids));
  292. $statuses = array_keys($this->data->get_form_statuses());
  293. // -------------------------------------
  294. // field order ids
  295. // -------------------------------------
  296. $all_field_ids = array();
  297. $all_order_ids = array();
  298. foreach ($forms_data as $form_data)
  299. {
  300. //this should always be true, but NEVER TRUST AN ELF
  301. if (isset($form_data['field_ids']) AND
  302. is_array($form_data['field_ids']))
  303. {
  304. $all_field_ids = array_merge(
  305. $all_field_ids,
  306. $form_data['field_ids']
  307. );
  308. $all_order_ids = array_merge(
  309. $all_order_ids,
  310. $this->actions()->pipe_split($form_data['field_order'])
  311. );
  312. }
  313. }
  314. $all_field_ids = array_unique($all_field_ids);
  315. $all_order_ids = array_unique($all_order_ids);
  316. sort($all_field_ids);
  317. // -------------------------------------
  318. // get field data
  319. // -------------------------------------
  320. $all_field_data = FALSE;
  321. if ( ! empty($all_field_ids))
  322. {
  323. $all_field_data = ee()->freeform_field_model
  324. ->key('field_id')
  325. ->where_in('field_id', $all_field_ids)
  326. ->get();
  327. }
  328. $field_data = array();
  329. if ($all_field_data)
  330. {
  331. foreach ($all_field_data as $row)
  332. {
  333. $field_data[$row['field_id']] = $row;
  334. }
  335. }
  336. // -------------------------------------
  337. // set tables
  338. // -------------------------------------
  339. ee()->freeform_entry_model->id($form_ids);
  340. // -------------------------------------
  341. // replace CURRENT_USER before we get
  342. // started because the minute we don't
  343. // someone is going to figure out
  344. // a way to need it in site_id=""
  345. // -------------------------------------
  346. $this->replace_current_user();
  347. // -------------------------------------
  348. // site ids
  349. // -------------------------------------
  350. //if its star, allow all
  351. if (ee()->TMPL->fetch_param('site_id') !== '*')
  352. {
  353. $site_id = $this->parse_numeric_array_param('site_id');
  354. //if this isn't false, its single or an array
  355. if ($site_id !== FALSE)
  356. {
  357. if (empty($site_id['ids']))
  358. {
  359. ee()->freeform_entry_model->reset();
  360. return $this->no_results_error();
  361. }
  362. else if ($site_id['not'])
  363. {
  364. ee()->freeform_entry_model->where_not_in(
  365. 'site_id',
  366. $site_id['ids']
  367. );
  368. }
  369. else
  370. {
  371. ee()->freeform_entry_model->where_in(
  372. 'site_id',
  373. $site_id['ids']
  374. );
  375. }
  376. }
  377. //default
  378. else
  379. {
  380. ee()->freeform_entry_model->where(
  381. 'site_id',
  382. ee()->config->item('site_id')
  383. );
  384. }
  385. }
  386. // -------------------------------------
  387. // entry ids
  388. // -------------------------------------
  389. $entry_id = $this->parse_numeric_array_param('entry_id');
  390. if ($entry_id !== FALSE)
  391. {
  392. if (empty($entry_id['ids']))
  393. {
  394. ee()->freeform_entry_model->reset();
  395. return $this->no_results_error();
  396. }
  397. else if ($entry_id['not'])
  398. {
  399. ee()->freeform_entry_model->where_not_in(
  400. 'entry_id',
  401. $entry_id['ids']
  402. );
  403. }
  404. else
  405. {
  406. ee()->freeform_entry_model->where_in(
  407. 'entry_id',
  408. $entry_id['ids']
  409. );
  410. }
  411. }
  412. // -------------------------------------
  413. // author ids
  414. // -------------------------------------
  415. $author_id = $this->parse_numeric_array_param('author_id');
  416. if ($author_id !== FALSE)
  417. {
  418. if (empty($author_id['ids']))
  419. {
  420. ee()->freeform_entry_model->reset();
  421. return $this->no_results_error();
  422. }
  423. else if ($author_id['not'])
  424. {
  425. ee()->freeform_entry_model->where_not_in(
  426. 'author_id',
  427. $author_id['ids']
  428. );
  429. }
  430. else
  431. {
  432. ee()->freeform_entry_model->where_in(
  433. 'author_id',
  434. $author_id['ids']
  435. );
  436. }
  437. }
  438. // -------------------------------------
  439. // {freeform:all_form_fields}
  440. // -------------------------------------
  441. $tagdata = $this->replace_all_form_fields(
  442. ee()->TMPL->tagdata,
  443. $field_data,
  444. $all_order_ids
  445. );
  446. // -------------------------------------
  447. // get standard columns and labels
  448. // -------------------------------------
  449. $standard_columns = array_keys(
  450. ee()->freeform_form_model->default_form_table_columns
  451. );
  452. $standard_columns[] = 'author';
  453. $column_labels = array();
  454. //keyed labels for the front end
  455. foreach ($standard_columns as $column_name)
  456. {
  457. $column_labels[$column_name] = lang($column_name);
  458. }
  459. // -------------------------------------
  460. // available fields
  461. // -------------------------------------
  462. //this makes the keys and values the same
  463. $available_fields = array_combine(
  464. $standard_columns,
  465. $standard_columns
  466. );
  467. $custom_fields = array();
  468. $field_descriptions = array();
  469. foreach ($field_data as $field_id => $f_data)
  470. {
  471. $fid = ee()->freeform_form_model->form_field_prefix . $field_id;
  472. //field_name => field_id_1, etc
  473. $available_fields[$f_data['field_name']] = $fid;
  474. //field_id_1 => field_id_1, etc
  475. $available_fields[$fid] = $fid;
  476. $custom_fields[] = $f_data['field_name'];
  477. //labels
  478. $column_labels[$f_data['field_name']] = $f_data['field_label'];
  479. $column_labels[$fid] = $f_data['field_label'];
  480. $field_descriptions[
  481. 'freeform:description:' . $f_data['field_name']
  482. ] = $f_data['field_description'];
  483. }
  484. // -------------------------------------
  485. // search:field_name="kittens"
  486. // -------------------------------------
  487. foreach (ee()->TMPL->tagparams as $key => $value)
  488. {
  489. if (substr($key, 0, 7) == 'search:')
  490. {
  491. $search_key = substr($key, 7);
  492. if (isset($available_fields[$search_key]))
  493. {
  494. ee()->freeform_entry_model->add_search(
  495. $available_fields[$search_key],
  496. $value
  497. );
  498. }
  499. }
  500. }
  501. // -------------------------------------
  502. // date range
  503. // -------------------------------------
  504. $date_range = ee()->TMPL->fetch_param('date_range');
  505. $date_range_start = ee()->TMPL->fetch_param('date_range_start');
  506. $date_range_end = ee()->TMPL->fetch_param('date_range_end');
  507. ee()->freeform_entry_model->date_where(
  508. $date_range,
  509. $date_range_start,
  510. $date_range_end
  511. );
  512. // -------------------------------------
  513. // complete
  514. // -------------------------------------
  515. $show_incomplete = ee()->TMPL->fetch_param('show_incomplete');
  516. if ($show_incomplete === 'only')
  517. {
  518. ee()->freeform_entry_model->where('complete', 'n');
  519. }
  520. //default unless show_incomplete="y"
  521. else if ( ! $this->check_yes($show_incomplete))
  522. {
  523. ee()->freeform_entry_model->where('complete', 'y');
  524. }
  525. // -------------------------------------
  526. // status
  527. // -------------------------------------
  528. $status = ee()->TMPL->fetch_param('status', 'open');
  529. if ($status !== 'all')
  530. {
  531. //make it an array either way
  532. $status = array_map('trim', $this->actions()->pipe_split($status));
  533. $approved = array_map('strtolower', $statuses);
  534. $search_status = array();
  535. //only keep legit ones
  536. foreach($status as $potential_status)
  537. {
  538. if (in_array(strtolower($potential_status), $approved))
  539. {
  540. $search_status[] = $potential_status;
  541. }
  542. }
  543. if ( ! empty($search_status))
  544. {
  545. ee()->freeform_entry_model->where_in(
  546. 'status',
  547. $search_status
  548. );
  549. }
  550. }
  551. // -------------------------------------
  552. // orderby/sort
  553. // -------------------------------------
  554. $sort = ee()->TMPL->fetch_param('sort');
  555. $orderby = ee()->TMPL->fetch_param('orderby');
  556. if ($orderby !== FALSE AND trim($orderby) !== '')
  557. {
  558. $orderby = $this->actions()->pipe_split(strtolower(trim($orderby)));
  559. array_walk($orderby, 'trim');
  560. // -------------------------------------
  561. // sort
  562. // -------------------------------------
  563. if ($sort !== FALSE AND trim($sort) !== '')
  564. {
  565. $sort = $this->actions()->pipe_split(strtolower(trim($sort)));
  566. array_walk($sort, 'trim');
  567. //correct sorts
  568. foreach ($sort as $key => $value)
  569. {
  570. if ( ! in_array($value, array('asc', 'desc')))
  571. {
  572. $sort[$key] = 'asc';
  573. }
  574. }
  575. }
  576. else
  577. {
  578. $sort = array('asc');
  579. }
  580. // -------------------------------------
  581. // add sorts and orderbys
  582. // -------------------------------------
  583. foreach ($orderby as $key => $value)
  584. {
  585. if ($value == 'random')
  586. {
  587. ee()->freeform_entry_model->order_by('', 'random');
  588. continue;
  589. }
  590. if (isset($available_fields[$value]))
  591. {
  592. //if the sort is not set, just use the first
  593. //really this should teach people to be more specific :p
  594. $temp_sort = isset($sort[$key]) ? $sort[$key] : $sort[0];
  595. ee()->freeform_entry_model->order_by(
  596. $available_fields[$value],
  597. $temp_sort
  598. );
  599. }
  600. }
  601. }
  602. //--------------------------------------
  603. // pagination start vars
  604. //--------------------------------------
  605. $limit = ee()->TMPL->fetch_param('limit', 50);
  606. $offset = ee()->TMPL->fetch_param('offset', 0);
  607. $row_count = 0;
  608. $total_entries = ee()->freeform_entry_model->count(array(), FALSE);
  609. $current_page = 0;
  610. if ($total_entries == 0)
  611. {
  612. ee()->freeform_entry_model->reset();
  613. return $this->no_results_error();
  614. }
  615. // -------------------------------------
  616. // pagination?
  617. // -------------------------------------
  618. $prefix = stristr($tagdata, LD . 'freeform:paginate' . RD);
  619. if ($limit > 0 AND ($total_entries - $offset) > $limit)
  620. {
  621. //get pagination info
  622. $pagination_data = $this->universal_pagination(array(
  623. 'total_results' => $total_entries,
  624. 'tagdata' => $tagdata,
  625. 'limit' => $limit,
  626. 'offset' => $offset,
  627. 'uri_string' => ee()->uri->uri_string,
  628. 'prefix' => 'freeform:',
  629. 'auto_paginate' => TRUE
  630. ));
  631. //if we paginated, sort the data
  632. if ($pagination_data['paginate'] === TRUE)
  633. {
  634. $tagdata = $pagination_data['tagdata'];
  635. $current_page = $pagination_data['pagination_page'];
  636. }
  637. }
  638. else
  639. {
  640. $this->paginate = FALSE;
  641. }
  642. ee()->freeform_entry_model->limit($limit, $current_page + $offset);
  643. // -------------------------------------
  644. // get data
  645. // -------------------------------------
  646. $result_array = ee()->freeform_entry_model->get();
  647. if (empty($result_array))
  648. {
  649. ee()->freeform_entry_model->reset();
  650. return $this->no_results_error();
  651. }
  652. $output_labels = array();
  653. //column labels for output
  654. foreach ($column_labels as $key => $value)
  655. {
  656. $output_labels['freeform:label:' . $key] = $value;
  657. }
  658. $count = $row_count;
  659. $variable_rows = array();
  660. $replace_tagdata = '';
  661. // -------------------------------------
  662. // allow pre_process
  663. // -------------------------------------
  664. $entry_ids = array();
  665. foreach ($result_array as $row)
  666. {
  667. if ( ! isset($entry_ids[$row['form_id']]))
  668. {
  669. $entry_ids[$row['form_id']] = array();
  670. }
  671. $entry_ids[$row['form_id']][] = $row['entry_id'];
  672. }
  673. // -------------------------------------
  674. // preprocess items
  675. // -------------------------------------
  676. // These are separated by form id so this
  677. // is not iterating over each entry id
  678. // but rather grouped by form.
  679. // -------------------------------------
  680. foreach ($entry_ids as $f_form_id => $f_entry_ids)
  681. {
  682. ee()->freeform_fields->apply_field_method(array(
  683. 'method' => 'pre_process_entries',
  684. 'form_id' => $f_form_id,
  685. 'form_data' => $forms_data,
  686. 'entry_id' => $f_entry_ids,
  687. 'field_data' => $field_data
  688. ));
  689. }
  690. // -------------------------------------
  691. // output
  692. // -------------------------------------
  693. $to_prefix = array(
  694. 'absolute_count',
  695. 'absolute_results',
  696. 'attachment_count',
  697. 'author_id',
  698. 'author',
  699. 'complete',
  700. 'edit_date',
  701. 'entry_date',
  702. 'entry_id',
  703. 'form_id',
  704. 'form_name',
  705. 'ip_address',
  706. 'reverse_count'
  707. );
  708. $absolute_count = $current_page + $offset;
  709. $total_results = count($result_array);
  710. $count = 0;
  711. // -------------------------------------
  712. // get file attachment count for entries
  713. // -------------------------------------
  714. $att_results = ee()->freeform_file_upload_model
  715. ->select('form_id, entry_id, COUNT(*) as file_count')
  716. ->where_in('form_id', $form_ids)
  717. ->group_by('form_id, entry_id')
  718. ->get();
  719. $attached_counts = array();
  720. if ( ! empty($att_results))
  721. {
  722. foreach ($att_results as $att_row)
  723. {
  724. if ( ! isset($attached_counts[$att_row['form_id']]))
  725. {
  726. $attached_counts[$att_row['form_id']] = array();
  727. }
  728. $attached_counts[$att_row['form_id']][$att_row['entry_id']] = $att_row['file_count'];
  729. }
  730. }
  731. // -------------------------------------
  732. // build results
  733. // -------------------------------------
  734. foreach ($result_array as $row)
  735. {
  736. //apply replace tag to our field data
  737. $field_parse = ee()->freeform_fields->apply_field_method(array(
  738. 'method' => 'replace_tag',
  739. 'form_id' => $row['form_id'],
  740. 'entry_id' => $row['entry_id'],
  741. 'form_data' => $forms_data,
  742. 'field_data' => $field_data,
  743. 'field_input_data' => $row,
  744. 'tagdata' => $tagdata
  745. ));
  746. $row = array_merge(
  747. $output_labels,
  748. $field_descriptions,
  749. $row,
  750. $field_parse['variables']
  751. );
  752. $row['attachment_count'] = isset($attached_counts[$row['form_id']][$row['entry_id']]) ?
  753. $attached_counts[$row['form_id']][$row['entry_id']] :
  754. 0;
  755. if ($replace_tagdata == '')
  756. {
  757. $replace_tagdata = $field_parse['tagdata'];
  758. }
  759. $row['freeform:form_name'] = $forms_data[$row['form_id']]['form_name'];
  760. $row['freeform:form_label'] = $forms_data[$row['form_id']]['form_label'];
  761. //prefix
  762. foreach ($row as $key => $value)
  763. {
  764. if ( ! preg_match('/^freeform:/', $key))
  765. {
  766. if (in_array($key, $custom_fields) AND
  767. ! isset($row['freeform:field:' . $key]))
  768. {
  769. $row['freeform:field:' . $key] = $value;
  770. }
  771. else if ( ! isset($row['freeform:' . $key]))
  772. {
  773. $row['freeform:' . $key] = $value;
  774. }
  775. unset($row[$key]);
  776. }
  777. }
  778. // -------------------------------------
  779. // other counts
  780. // -------------------------------------
  781. $row['freeform:reverse_count'] = $total_results - $count++;
  782. $row['freeform:absolute_count'] = ++$absolute_count;
  783. $row['freeform:absolute_results'] = $total_entries;
  784. $variable_rows[] = $row;
  785. }
  786. $tagdata = $replace_tagdata;
  787. $prefixed_tags = array(
  788. 'count',
  789. 'switch',
  790. 'total_results'
  791. );
  792. $tagdata = $this->tag_prefix_replace('freeform:', $prefixed_tags, $tagdata);
  793. //this should handle backspacing as well
  794. $tagdata = ee()->TMPL->parse_variables($tagdata, $variable_rows);
  795. $tagdata = $this->tag_prefix_replace('freeform:', $prefixed_tags, $tagdata, TRUE);
  796. // -------------------------------------
  797. // add pagination
  798. // -------------------------------------
  799. //prefix or no prefix?
  800. if ($prefix)
  801. {
  802. $tagdata = $this->parse_pagination(array(
  803. 'prefix' => 'freeform:',
  804. 'tagdata' => $tagdata
  805. ));
  806. }
  807. else
  808. {
  809. $tagdata = $this->parse_pagination(array(
  810. 'tagdata' => $tagdata
  811. ));
  812. }
  813. return $tagdata;
  814. }
  815. //END entries
  816. // --------------------------------------------------------------------
  817. /**
  818. * Freeform:Form
  819. * {exp:freeform:form}
  820. *
  821. * @access public
  822. * @param bool $edit edit mode? external for security
  823. * @param bool $preview preview mode?
  824. * @param mixed $preview_fields extra preview fields?
  825. * @return string tagdata
  826. */
  827. public function form($edit = FALSE, $preview = FALSE, $preview_fields = FALSE)
  828. {
  829. if ($this->check_yes(ee()->TMPL->fetch_param('require_logged_in')) AND
  830. ee()->session->userdata['member_id'] == '0')
  831. {
  832. return $this->no_results_error('not_logged_in');
  833. }
  834. // -------------------------------------
  835. // form id
  836. // -------------------------------------
  837. $form_id = $this->form_id(FALSE, FALSE);
  838. if ( ! $form_id)
  839. {
  840. return $this->no_results_error('invalid_form_id');
  841. }
  842. // -------------------------------------
  843. // libs, helpers, etc
  844. // -------------------------------------
  845. ee()->load->model('freeform_form_model');
  846. ee()->load->model('freeform_field_model');
  847. ee()->load->library('freeform_forms');
  848. ee()->load->library('freeform_fields');
  849. ee()->load->helper('form');
  850. // -------------------------------------
  851. // build query
  852. // -------------------------------------
  853. $this->form_data = $form_data = $this->data->get_form_info($form_id);
  854. // -------------------------------------
  855. // preview fields? (composer preview)
  856. // -------------------------------------
  857. if ( ! empty($preview_fields))
  858. {
  859. ee()->load->model('freeform_field_model');
  860. $valid_preview_fields = ee()->freeform_field_model
  861. ->where_in('field_id', $preview_fields)
  862. ->key('field_id')
  863. ->get();
  864. if ($valid_preview_fields)
  865. {
  866. foreach ($valid_preview_fields as $p_field_id => $p_field_data)
  867. {
  868. $p_field_data['preview'] = TRUE;
  869. $form_data['fields'][$p_field_id] = $p_field_data;
  870. }
  871. }
  872. }
  873. // -------------------------------------
  874. // form data
  875. // -------------------------------------
  876. $this->params['form_id'] = $form_id;
  877. // -------------------------------------
  878. // edit?
  879. // -------------------------------------
  880. $entry_id = 0;
  881. $edit_data = array();
  882. $this->params['edit'] = $edit;
  883. $this->params['entry_id'] = $entry_id;
  884. // -------------------------------------
  885. // replace CURRENT_USER everywhere
  886. // -------------------------------------
  887. $this->replace_current_user();
  888. // -------------------------------------
  889. // default params
  890. // -------------------------------------
  891. $this->default_mp_page_marker = 'page';
  892. $this->set_form_params(TRUE);
  893. // ----------------------------------------
  894. // Check for duplicate
  895. // ----------------------------------------
  896. $duplicate = FALSE;
  897. //we can only prevent dupes on entry like this
  898. if ( ! $edit AND $this->params['prevent_duplicate_on'])
  899. {
  900. if ( in_array(
  901. $this->params['prevent_duplicate_on'],
  902. array('member_id', 'ip_address'),
  903. TRUE
  904. ))
  905. {
  906. $duplicate = ee()->freeform_forms->check_duplicate(
  907. $form_id,
  908. $this->params['prevent_duplicate_on'],
  909. '',
  910. $this->params['prevent_duplicate_per_site']
  911. );
  912. }
  913. }
  914. // ----------------------------------------
  915. // duplicate?
  916. // ----------------------------------------
  917. if ($duplicate)
  918. {
  919. if ($this->params['duplicate_redirect'] !== '')
  920. {
  921. ee()->functions->redirect(
  922. $this->prep_url(
  923. $this->params['duplicate_redirect'],
  924. $this->params['secure_duplicate_redirect']
  925. )
  926. );
  927. return $this->do_exit();
  928. }
  929. else if ($this->params['error_on_duplicate'])
  930. {
  931. return $this->no_results_error('no_duplicates');
  932. }
  933. /*else if (preg_match(
  934. '/' . LD . 'if freeform_duplicate' . RD . '(*?)' '/',
  935. ee()->TMPL->tagdata, ))
  936. {
  937. }*/
  938. }
  939. // -------------------------------------
  940. // check user email field
  941. // if this is from form prefs, its an ID
  942. // -------------------------------------
  943. $valid_user_email_field = FALSE;
  944. foreach ($form_data['fields'] as $field_id => $field_data)
  945. {
  946. if ($this->params['user_email_field'] == $field_data['field_name'] OR
  947. $this->params['user_email_field'] == $field_id)
  948. {
  949. $valid_user_email_field = TRUE;
  950. //in case the setting is an id
  951. $this->params['user_email_field'] = $field_data['field_name'];
  952. break;
  953. }
  954. }
  955. // if it doesn't exist in the form, lets blank it
  956. $this->params['user_email_field'] = (
  957. $valid_user_email_field ?
  958. $this->params['user_email_field'] :
  959. ''
  960. );
  961. $this->edit = $edit;
  962. // ----------------------------------------
  963. // 'freeform_module_form_begin' hook.
  964. // - This allows developers to change data before form processing.
  965. // ----------------------------------------
  966. if (ee()->extensions->active_hook('freeform_module_form_begin') === TRUE)
  967. {
  968. ee()->extensions->universal_call(
  969. 'freeform_module_form_begin',
  970. $this
  971. );
  972. if (ee()->extensions->end_script === TRUE) return;
  973. }
  974. // ----------------------------------------
  975. // -------------------------------------
  976. // start form
  977. // -------------------------------------
  978. $tagdata = ee()->TMPL->tagdata;
  979. $return = '';
  980. $hidden_fields = array();
  981. $outer_template_vars = array();
  982. $variables = array();
  983. $page_total = 1;
  984. $current_page = 0;
  985. $last_page = TRUE;
  986. $multipage = $this->params['multipage'];
  987. // -------------------------------------
  988. // check if this is multi-page
  989. // -------------------------------------
  990. $current_page = 1;
  991. // -------------------------------------
  992. // set for hooks
  993. // -------------------------------------
  994. $this->multipage = $multipage;
  995. $this->last_page = $last_page;
  996. // -------------------------------------
  997. // check again for captcha now that
  998. // tagdata has been adjusted
  999. // -------------------------------------
  1000. if ($this->params['require_captcha'])
  1001. {
  1002. $this->params['require_captcha'] = (
  1003. $this->require_captcha() &&
  1004. stristr($tagdata, LD . 'freeform:captcha' . RD) != FALSE
  1005. );
  1006. }
  1007. // -------------------------------------
  1008. // submit
  1009. // -------------------------------------
  1010. //standard submits
  1011. $variables['freeform:submit'] = form_submit('submit', lang('submit'));
  1012. //replace submit buttons that have args
  1013. $tagdata = $this->replace_submit(array(
  1014. 'tag' => 'freeform:submit',
  1015. 'pre_args' => array(
  1016. 'name' => 'submit',
  1017. 'value' => lang('submit')
  1018. ),
  1019. 'tagdata' => $tagdata
  1020. ));
  1021. // -------------------------------------
  1022. // other random vars
  1023. // -------------------------------------
  1024. $variables['freeform:submit_previous'] = '';
  1025. $variables['freeform:duplicate'] = $duplicate;
  1026. $variables['freeform:not_duplicate'] = ! $duplicate;
  1027. $variables['freeform:form_label'] = $form_data['form_label'];
  1028. $variables['freeform:form_description'] = $form_data['form_description'];
  1029. $variables['freeform:last_page'] = $last_page;
  1030. $variables['freeform:current_page'] = $current_page;
  1031. // -------------------------------------
  1032. // display fields
  1033. // -------------------------------------
  1034. $field_error_data = array();
  1035. $general_error_data = array();
  1036. $field_input_data = array();
  1037. // -------------------------------------
  1038. // inline errors?
  1039. // -------------------------------------
  1040. if ($this->params['inline_errors'] AND
  1041. $this->is_positive_intlike(
  1042. ee()->session->flashdata('freeform_errors')
  1043. )
  1044. )
  1045. {
  1046. ee()->load->model('freeform_param_model');
  1047. $error_query = ee()->freeform_param_model->get_row(
  1048. ee()->session->flashdata('freeform_errors')
  1049. );
  1050. if ($error_query !== FALSE)
  1051. {
  1052. $potential_error_data = json_decode($error_query['data'], TRUE);
  1053. //specific field errors
  1054. if (isset($potential_error_data['field_errors']))
  1055. {
  1056. $field_error_data = $potential_error_data['field_errors'];
  1057. }
  1058. //errors that aren't field based
  1059. if (isset($potential_error_data['general_errors']))
  1060. {
  1061. $general_error_data = $potential_error_data['general_errors'];
  1062. }
  1063. //gets inputs for repopulation
  1064. if (isset($potential_error_data['inputs']))
  1065. {
  1066. $field_input_data = $potential_error_data['inputs'];
  1067. }
  1068. //restore recipient_emails
  1069. if (! empty($potential_error_data['stored_data']['recipient_emails']))
  1070. {
  1071. $previous_inputs['hash_stored_data']['recipient_emails'] =
  1072. $potential_error_data['stored_data']['recipient_emails'];
  1073. }
  1074. //restore user_recipient_emails
  1075. if (! empty($potential_error_data['stored_data']['user_recipient_emails']))
  1076. {
  1077. $previous_inputs['hash_stored_data']['user_recipient_emails'] =
  1078. $potential_error_data['stored_data']['user_recipient_emails'];
  1079. }
  1080. }
  1081. }
  1082. //END if ($this->params['inline_errors']
  1083. // -------------------------------------
  1084. // build field variables
  1085. // -------------------------------------
  1086. foreach ($form_data['fields'] as $field_id => $field_data)
  1087. {
  1088. // -------------------------------------
  1089. // label?
  1090. // -------------------------------------
  1091. $error = '';
  1092. if (isset($field_error_data[$field_data['field_name']]))
  1093. {
  1094. $error = is_array($field_error_data[$field_data['field_name']]) ?
  1095. implode(', ', $field_error_data[$field_data['field_name']]) :
  1096. $field_error_data[$field_data['field_name']];
  1097. }
  1098. // -------------------------------------
  1099. // variables for later parsing
  1100. // -------------------------------------
  1101. $variables['freeform:error:' . $field_data['field_name']] = $error;
  1102. $variables['freeform:label:' . $field_data['field_name']] = $field_data['field_label'];
  1103. $variables['freeform:description:' . $field_data['field_name']] = $field_data['field_description'];
  1104. // -------------------------------------
  1105. // values?
  1106. // -------------------------------------
  1107. $col_name = ee()->freeform_form_model->form_field_prefix . $field_id;
  1108. // -------------------------------------
  1109. // multipage previous inputs?
  1110. // -------------------------------------
  1111. $possible = (
  1112. isset($previous_inputs[$col_name]) ?
  1113. $previous_inputs[$col_name] :
  1114. (
  1115. isset($previous_inputs[$field_data['field_name']]) ?
  1116. $previous_inputs[$field_data['field_name']] :
  1117. ''
  1118. )
  1119. );
  1120. $possible = $this->prep_multi_item_data($possible, $field_data['field_type']);
  1121. $variables['freeform:mp_data:' . $field_data['field_name']] = $possible;
  1122. }
  1123. //END foreach ($form_data['fields'] as $field_id => $field_data)
  1124. // -------------------------------------
  1125. // This is done after edit data in
  1126. // cause they edited data, but had an error
  1127. // in their edits and we are now in
  1128. // inline error mode
  1129. // -------------------------------------
  1130. if ( ! empty($edit_data))
  1131. {
  1132. $field_input_data = array_merge($edit_data, $field_input_data);
  1133. }
  1134. else if ( ! empty($previous_inputs))
  1135. {
  1136. $field_input_data = array_merge($previous_inputs, $field_input_data);
  1137. }
  1138. // -------------------------------------
  1139. // recipient emails from multipage?
  1140. // -------------------------------------
  1141. $variables['freeform:mp_data:user_recipient_emails'] = '';
  1142. if (isset($previous_inputs['hash_stored_data']['user_recipient_emails']) AND
  1143. is_array($previous_inputs['hash_stored_data']['user_recipient_emails']))
  1144. {
  1145. $variables['freeform:mp_data:user_recipient_emails'] = implode(
  1146. ', ',
  1147. $previous_inputs['hash_stored_data']['user_recipient_emails']
  1148. );
  1149. }
  1150. // -------------------------------------
  1151. // freeform:all_form_fields
  1152. // -------------------------------------
  1153. $tagdata = $this->replace_all_form_fields(
  1154. $tagdata,
  1155. $form_data['fields'],
  1156. $form_data['field_order'],
  1157. $field_input_data
  1158. );
  1159. // -------------------------------------
  1160. // general errors
  1161. // -------------------------------------
  1162. if ( ! empty($general_error_data))
  1163. {
  1164. //the error array might have sub arrays
  1165. //so we need to flatten
  1166. $_general_error_data = array();
  1167. foreach ($general_error_data as $error_set => $error_data)
  1168. {
  1169. if (is_array($error_data))
  1170. {
  1171. foreach ($error_data as $sub_key => $sub_error)
  1172. {
  1173. $_general_error_data[] = array(
  1174. 'freeform:error_message' => $sub_error
  1175. );
  1176. }
  1177. }
  1178. else
  1179. {
  1180. $_general_error_data[] = array(
  1181. 'freeform:error_message' => $error_data
  1182. );
  1183. }
  1184. }
  1185. $general_error_data = $_general_error_data;
  1186. }
  1187. $variables['freeform:general_errors'] = $general_error_data;
  1188. $variables['freeform:field_errors'] = ! empty($field_error_data);
  1189. //have to do this so the conditional will work,
  1190. //seems that parse variables doesn't think a non-empty array = YES
  1191. $tagdata = ee()->functions->prep_conditionals(
  1192. $tagdata,
  1193. array(
  1194. 'freeform:general_errors' => ! empty($general_error_data),
  1195. 'freeform:field_errors' => ! empty($field_error_data)
  1196. )
  1197. );
  1198. // -------------------------------------
  1199. // apply replace tag to our field data
  1200. // -------------------------------------
  1201. $field_parse = ee()->freeform_fields->apply_field_method(array(
  1202. 'method' => 'display_field',
  1203. 'form_id' => $form_id,
  1204. 'entry_id' => $entry_id,
  1205. 'form_data' => $form_data,
  1206. 'field_input_data' => $field_input_data,
  1207. 'tagdata' => $tagdata
  1208. ));
  1209. $this->multipart = $field_parse['multipart'];
  1210. $variables = array_merge($variables, $field_parse['variables']);
  1211. $tagdata = $field_parse['tagdata'];
  1212. // -------------------------------------
  1213. // dynamic recipient list
  1214. // -------------------------------------
  1215. $this->params['recipients'] = (
  1216. ! in_array(ee()->TMPL->fetch_param('recipients'), array(FALSE, ''))
  1217. );
  1218. //preload list with usable info if so
  1219. $this->params['recipients_list'] = array();
  1220. if ( $this->params['recipients'] )
  1221. {
  1222. $i = 1;
  1223. $while_limit = 1000;
  1224. $counter = 0;
  1225. while ( ! in_array(ee()->TMPL->fetch_param('recipient' . $i), array(FALSE, '')) )
  1226. {
  1227. $recipient = explode('|', ee()->TMPL->fetch_param('recipient' . $i));
  1228. //has a name?
  1229. if ( count($recipient) > 1)
  1230. {
  1231. $recipient_name = trim($recipient[0]);
  1232. $recipient_email = trim($recipient[1]);
  1233. }
  1234. //no name, we assume its just an email
  1235. //(though, this makes little sense, it needs a name to be useful)
  1236. else
  1237. {
  1238. $recipient_name = '';
  1239. $recipient_email = trim($recipient[0]);
  1240. }
  1241. $recipient_selected = FALSE;
  1242. if (isset($previous_inputs['hash_stored_data']['recipient_emails']) AND
  1243. is_array($previous_inputs['hash_stored_data']['recipient_emails']))
  1244. {
  1245. $recipient_selected = in_array(
  1246. $recipient_email,
  1247. $previous_inputs['hash_stored_data']['recipient_emails']
  1248. );
  1249. }
  1250. //add to list
  1251. $this->params['recipients_list'][$i] = array(
  1252. 'name' => $recipient_name,
  1253. 'email' => $recipient_email,
  1254. //because this wasn't being unique enough
  1255. //on stupid windows servers *sigh*
  1256. 'key' => uniqid('', true),
  1257. 'selected' => $recipient_selected
  1258. );
  1259. $i++;
  1260. //In case fetch_param ever defaults to something
  1261. //thats not falsy.
  1262. if (++$counter >= $while_limit)
  1263. {
  1264. break;
  1265. }
  1266. }
  1267. //if we end up with nothing, then lets not attempt later
  1268. if (empty($this->params['recipients_list']))
  1269. {
  1270. $this->params['recipients'] = FALSE;
  1271. }
  1272. }
  1273. // ----------------------------------------
  1274. // parse {freeform:captcha}
  1275. // ----------------------------------------
  1276. $variables['freeform:captcha'] = FALSE;
  1277. if ($this->params['require_captcha'])
  1278. {
  1279. $variables['freeform:captcha'] = ee()->functions->create_captcha();
  1280. // -------------------------------------
  1281. // IF there is no captcha present
  1282. // in this tagdata, we don't want
  1283. // to require people to input it.
  1284. // Thats asking for errors.
  1285. // Usually this occurs when someone is
  1286. // trying to force captcha but the
  1287. // member is logged in and EE wont
  1288. // output captcha for members unless
  1289. // captcha_require_members is enabled.
  1290. // -------------------------------------
  1291. if (stristr($tagdata, LD . 'freeform:captcha' . RD) == FALSE OR
  1292. empty($variables['freeform:captcha']))
  1293. {
  1294. $this->params['require_captcha'] = FALSE;
  1295. }
  1296. }
  1297. // -------------------------------------
  1298. // dynamic recipient tagdata
  1299. // -------------------------------------
  1300. if ( $this->params['recipients'] AND
  1301. count($this->params['recipients_list']) > 0)
  1302. {
  1303. $variables['freeform_recipients'] = array();
  1304. $recipient_list = $this->params['recipients_list'];
  1305. //dynamic above starts with 1, so does this
  1306. for ( $i = 1, $l = count($recipient_list); $i <= $l; $i++ )
  1307. {
  1308. $variables['freeform:recipient_name' . $i] = $recipient_list[$i]['name'];
  1309. $variables['freeform:recipient_value' . $i] = $recipient_list[$i]['key'];
  1310. $variables['freeform:recipient_selected' . $i] = $recipient_list[$i]['selected'];
  1311. $variables['freeform:recipients'][] = array(
  1312. 'freeform:recipient_name' => $recipient_list[$i]['name'],
  1313. 'freeform:recipient_value' => $recipient_list[$i]['key'],
  1314. 'freeform:recipient_count' => $i,
  1315. //selected from hash data from multipages
  1316. 'freeform:recipient_selected' => $recipient_list[$i]['selected']
  1317. );
  1318. }
  1319. }
  1320. // -------------------------------------
  1321. // status pairs
  1322. // -------------------------------------
  1323. $tagdata = $this->parse_status_tags($tagdata);
  1324. // ----------------------------------------
  1325. // 'freeform_module_pre_form_parse' hook.
  1326. // - This allows developers to change data before tagdata processing.
  1327. // ----------------------------------------
  1328. $this->variables = $variables;
  1329. if (ee()->extensions->active_hook('freeform_module_pre_form_parse') === TRUE)
  1330. {
  1331. $backup_tagdata = $tagdata;
  1332. $tagdata = ee()->extensions->universal_call(
  1333. 'freeform_module_pre_form_parse',
  1334. $tagdata,
  1335. $this
  1336. );
  1337. if (ee()->extensions->end_script === TRUE) return;
  1338. //valid data?
  1339. if ( (! is_string($tagdata) OR empty($tagdata)) AND
  1340. $this->check_yes($this->preference('hook_data_protection')))
  1341. {
  1342. $tagdata = $backup_tagdata;
  1343. }
  1344. }
  1345. // ----------------------------------------
  1346. //extra precaution in case someone hoses this
  1347. if (isset($this->variables) AND is_array($this->variables))
  1348. {
  1349. $variables = $this->variables;
  1350. }
  1351. // -------------------------------------
  1352. // parse external vars
  1353. // -------------------------------------
  1354. $outer_template_vars['freeform:form_id'] = $form_id;
  1355. $outer_template_vars['freeform:form_page'] = $current_page;
  1356. $outer_template_vars['freeform:form_page_total'] = $page_total;
  1357. $outer_template_vars['freeform:form_name'] = $form_data['form_name'];
  1358. $outer_template_vars['freeform:form_label'] = $form_data['form_label'];
  1359. ee()->TMPL->template = ee()->functions->prep_conditionals(
  1360. ee()->TMPL->template,
  1361. $outer_template_vars
  1362. );
  1363. ee()->TMPL->template = ee()->functions->var_swap(
  1364. ee()->TMPL->template,
  1365. $outer_template_vars
  1366. );
  1367. // -------------------------------------
  1368. // parse all vars
  1369. // -------------------------------------
  1370. $tagdata = ee()->TMPL->parse_variables(
  1371. $tagdata,
  1372. array(array_merge($outer_template_vars,$variables))
  1373. );
  1374. // -------------------------------------
  1375. // This doesn't force an ajax request
  1376. // but instead forces it _not_ to be
  1377. // if the ajax param = 'no'.
  1378. // $this->params['ajax'] defaults to
  1379. // boolean true, so this will only
  1380. // happen if someone adds ajax="no".
  1381. // -------------------------------------
  1382. if ( ! $this->params['ajax'])
  1383. {
  1384. $hidden_fields['ajax_request'] = 'no';
  1385. }
  1386. //-------------------------------------
  1387. // build form
  1388. //-------------------------------------
  1389. $return .= $this->build_form(array(
  1390. 'action' => $this->get_action_url('save_form'),
  1391. 'method' => 'post',
  1392. 'hidden_fields' => array_merge($hidden_fields, array(
  1393. // no more params can be set after this
  1394. 'params_id' => $this->insert_params(),
  1395. )),
  1396. 'tagdata' => $tagdata
  1397. ));
  1398. // ----------------------------------------
  1399. // 'freeform_module_form_end' hook.
  1400. // - This allows developers to change the form before output.
  1401. // ----------------------------------------
  1402. if (ee()->extensions->active_hook('freeform_module_form_end') === TRUE)
  1403. {
  1404. $backup_return = $return;
  1405. $return = ee()->extensions->universal_call(
  1406. 'freeform_module_form_end',
  1407. $return,
  1408. $this
  1409. );
  1410. if (ee()->extensions->end_script === TRUE) return;
  1411. //valid data?
  1412. if ( (! is_string($return) OR empty($return)) AND
  1413. $this->check_yes($this->preference('hook_data_protection')))
  1414. {
  1415. $return = $backup_return;
  1416. }
  1417. }
  1418. // ----------------------------------------
  1419. return $return;
  1420. }
  1421. //END form
  1422. // -------------------------------------
  1423. // action requests
  1424. // -------------------------------------
  1425. // --------------------------------------------------------------------
  1426. /**
  1427. * ajax_validate
  1428. *
  1429. * does a save form that stops after validation
  1430. *
  1431. * @access public
  1432. * @return mixed ajax request
  1433. */
  1434. public function ajax_validate_form()
  1435. {
  1436. return $this->save_form(TRUE);
  1437. }
  1438. //END ajax_validate
  1439. // --------------------------------------------------------------------
  1440. /**
  1441. * save_form
  1442. *
  1443. * form save from front_end/action request
  1444. *
  1445. * @access public
  1446. * @param bool validate only
  1447. * @return null
  1448. */
  1449. public function save_form($validate_only = FALSE)
  1450. {
  1451. if ( ! $validate_only AND REQ !== 'ACTION' AND ! $this->test_mode)
  1452. {
  1453. return;
  1454. }
  1455. ee()->load->library('freeform_forms');
  1456. ee()->load->library('freeform_fields');
  1457. ee()->load->model('freeform_form_model');
  1458. if (ee()->input->get_post('params_id') === FALSE)
  1459. {
  1460. return $this->pre_validation_error(
  1461. lang('missing_post_data') . ' - params_id'
  1462. );
  1463. }
  1464. // -------------------------------------
  1465. // require logged in?
  1466. // -------------------------------------
  1467. if ($this->param('require_logged_in') AND
  1468. ee()->session->userdata['member_id'] == '0')
  1469. {
  1470. return $this->pre_validation_error(
  1471. lang('not_authorized') . ' - ' .
  1472. lang('not_logged_in')
  1473. );
  1474. }
  1475. // -------------------------------------
  1476. // blacklist, banned
  1477. // -------------------------------------
  1478. if (ee()->session->userdata['is_banned'] OR (
  1479. $this->check_yes(ee()->blacklist->blacklisted) AND
  1480. $this->check_no(ee()->blacklist->whitelisted)
  1481. )
  1482. )
  1483. {
  1484. return $this->pre_validation_error(
  1485. lang('not_authorized') . ' - ' .
  1486. lang('reason_banned')
  1487. );
  1488. }
  1489. // -------------------------------------
  1490. // require ip? (except admin)
  1491. // -------------------------------------
  1492. if ($this->param('require_ip'))
  1493. {
  1494. if (ee()->input->ip_address() == '0.0.0.0')
  1495. {
  1496. return $this->pre_validation_error(
  1497. lang('not_authorized') . ' - ' .
  1498. lang('reason_ip_required')
  1499. );
  1500. }
  1501. }
  1502. // -------------------------------------
  1503. // Is the nation of the user banned?
  1504. // -------------------------------------
  1505. if ($this->nation_ban_check(FALSE))
  1506. {
  1507. return $this->pre_validation_error(
  1508. lang('not_authorized') . ' - ' .
  1509. ee()->config->item('ban_message')
  1510. );
  1511. }
  1512. // -------------------------------------
  1513. // valid form id
  1514. // -------------------------------------
  1515. $form_id = $this->form_id(FALSE, FALSE);
  1516. if ( ! $form_id)
  1517. {
  1518. return $this->pre_validation_error(lang('invalid_form_id'));
  1519. }
  1520. // -------------------------------------
  1521. // is this an edit? entry_id
  1522. // -------------------------------------
  1523. $entry_id = $this->entry_id();
  1524. $edit = $this->is_positive_intlike($entry_id);
  1525. // -------------------------------------
  1526. // for multipage check later
  1527. // -------------------------------------
  1528. $multipage = $this->param('multipage');
  1529. $current_page = $this->param('current_page');
  1530. $last_page = $this->param('last_page');
  1531. $previous_inputs = array();
  1532. // -------------------------------------
  1533. // form data
  1534. // -------------------------------------
  1535. $this->form_data = $form_data = $this->data->get_form_info($form_id);
  1536. $field_labels = array();
  1537. $valid_fields = array();
  1538. $column_names = array();
  1539. foreach ( $form_data['fields'] as $row)
  1540. {
  1541. $field_labels[$row['field_name']] = $row['field_label'];
  1542. $valid_fields[] = $row['field_name'];
  1543. //fill previous inputs names correctly
  1544. $column_name = 'form_field_' . $row['field_id'];
  1545. if (isset($previous_inputs[$column_name]))
  1546. {
  1547. $previous_inputs[$row['field_name']] = $previous_inputs[$column_name];
  1548. }
  1549. $column_names[$row['field_name']] = $column_name;
  1550. }
  1551. // -------------------------------------
  1552. // for hooks
  1553. // -------------------------------------
  1554. $this->edit = $edit;
  1555. $this->multipage = $multipage;
  1556. $this->last_page = $last_page;
  1557. // -------------------------------------
  1558. // user email max/spam count
  1559. // -------------------------------------
  1560. ee()->load->library('freeform_notifications');
  1561. if ($last_page AND ($this->param('recipient_user_input') OR
  1562. $this->param('recipients')) AND
  1563. ee()->freeform_notifications->check_spam_interval($form_id)
  1564. )
  1565. {
  1566. return $this->pre_validation_error(
  1567. lang('not_authorized') . ' - ' .
  1568. lang('email_limit_exceeded')
  1569. );
  1570. }
  1571. // -------------------------------------
  1572. // Check for duplicate
  1573. // -------------------------------------
  1574. $duplicate = FALSE;
  1575. if ($this->param('prevent_duplicate_on'))
  1576. {
  1577. $duplicate = ee()->freeform_forms->check_duplicate(
  1578. $form_id,
  1579. $this->param('prevent_duplicate_on'),
  1580. ee()->input->get_post(
  1581. $this->param('prevent_duplicate_on'),
  1582. TRUE
  1583. ),
  1584. $this->param('prevent_duplicate_per_site')
  1585. );
  1586. }
  1587. if ($duplicate)
  1588. {
  1589. return $this->pre_validation_error(lang('no_duplicates'));
  1590. }
  1591. // -------------------------------------
  1592. // pre xid check
  1593. // -------------------------------------
  1594. // we aren't going to delete just yet
  1595. // because if they have input errors
  1596. // then we want to keep this xid for a bit
  1597. // and only delete xid on success
  1598. // -------------------------------------
  1599. // EE 2.7+ does this automatically for
  1600. // all POSTS front end and back now
  1601. // so this is going to cause errors
  1602. // if we check it there.
  1603. // -------------------------------------
  1604. if (version_compare($this->ee_version, '2.7.0', '<') &&
  1605. ! ee()->security->check_xid(ee()->input->post('XID')))
  1606. {
  1607. return $this->pre_validation_error(
  1608. lang('not_authorized') . ' - ' .
  1609. lang('reason_secure_form_timeout')
  1610. );
  1611. }
  1612. // -------------------------------------
  1613. // pre-validate hook
  1614. // -------------------------------------
  1615. $errors = array();
  1616. //have to do this weird for backward compat
  1617. $this->field_errors = array();
  1618. if (ee()->extensions->active_hook('freeform_module_validate_begin') === TRUE)
  1619. {
  1620. $backup_errors = $errors;
  1621. $errors = ee()->extensions->universal_call(
  1622. 'freeform_module_validate_begin',
  1623. $errors,
  1624. $this
  1625. );
  1626. if (ee()->extensions->end_script === TRUE) return;
  1627. //valid data?
  1628. if ( ! is_array($errors) AND
  1629. $this->check_yes($this->preference('hook_data_protection')))
  1630. {
  1631. $errors = $backup_errors;
  1632. }
  1633. }
  1634. // -------------------------------------
  1635. // require fields
  1636. // -------------------------------------
  1637. if ($this->param('required'))
  1638. {
  1639. $required = $this->actions()->pipe_split($this->param('required'));
  1640. foreach ($required as $required_field)
  1641. {
  1642. //require need to work for recipients and recipient email user
  1643. $valid_require = array_merge(
  1644. $valid_fields,
  1645. array('recipient_email_user', 'recipient_email')
  1646. );
  1647. $require_labels = $field_labels;
  1648. $require_labels['recipient_email_user'] = lang('user_recipients');
  1649. $require_labels['recipient_email'] = lang('dynamic_recipients');
  1650. //just in case someone misspelled a require
  1651. //or removes a field after making the require list
  1652. if ( ! in_array($required_field, $valid_require))
  1653. {
  1654. continue;
  1655. }
  1656. $gp_value = ee()->input->get_post($required_field);
  1657. if ( (
  1658. //empty array
  1659. (is_array($gp_value) AND count($gp_value) < 1) OR
  1660. //empty string or false
  1661. ( ! is_array($gp_value) AND trim((string) $gp_value) === '') OR
  1662. //recipient email <select> default is '0'
  1663. (
  1664. $required_field === 'recipient_email' AND
  1665. $gp_value === '0'
  1666. )
  1667. )
  1668. //required field could be a file
  1669. //check to see if something uploaded for that name
  1670. AND ! $this->actions()->file_upload_present(
  1671. $required_field,
  1672. $previous_inputs
  1673. )
  1674. )
  1675. {
  1676. $this->field_errors[
  1677. $required_field
  1678. ] = lang('required_field_missing');
  1679. //only want the postfixing of errors
  1680. //if we are sending to general errors screen
  1681. //or an error page
  1682. //the second conditional is for people requesting
  1683. //the custom error page via ajax
  1684. if ( ! $this->param('inline_errors') AND
  1685. ! ($this->is_ajax_request() AND
  1686. ! trim($this->param('error_page'))))
  1687. {
  1688. $this->field_errors[$required_field] .= ': '.
  1689. $require_labels[$required_field];
  1690. }
  1691. }
  1692. }
  1693. }
  1694. // -------------------------------------
  1695. // matching fields
  1696. // -------------------------------------
  1697. if ($this->param('matching_fields'))
  1698. {
  1699. $matching_fields = $this->actions()->pipe_split($this->param('matching_fields'));
  1700. foreach ($matching_fields as $match_field)
  1701. {
  1702. //just in case someone misspelled a require
  1703. //or removes a field after making the require list
  1704. if ( ! in_array($match_field, $valid_fields))
  1705. {
  1706. continue;
  1707. }
  1708. //array comparison is correct in PHP and this should work
  1709. //no matter what.
  1710. //normal validation will fix other issues
  1711. if ( ee()->input->get_post($match_field) == FALSE OR
  1712. ee()->input->get_post($match_field . '_confirm') == FALSE OR
  1713. ee()->input->get_post($match_field) !==
  1714. ee()->input->get_post($match_field . '_confirm')
  1715. )
  1716. {
  1717. $this->field_errors[$match_field] = lang('fields_do_not_match') .
  1718. $field_labels[$match_field] .
  1719. ' | ' .
  1720. $field_labels[$match_field] .
  1721. ' ' .
  1722. lang('confirm');
  1723. }
  1724. }
  1725. }
  1726. // -------------------------------------
  1727. // validate dynamic recipients
  1728. // no actual validation errors
  1729. // will throw here, but in case we do
  1730. // in the future
  1731. // -------------------------------------
  1732. $recipient_emails = array();
  1733. if ($this->param('recipients'))
  1734. {
  1735. $recipient_email_input = ee()->input->get_post('recipient_email');
  1736. if ( ! in_array($recipient_email_input, array(FALSE, ''), TRUE))
  1737. {
  1738. if ( ! is_array($recipient_email_input))
  1739. {
  1740. $recipient_email_input = array($recipient_email_input);
  1741. }
  1742. // recipients are encoded, so lets check for keys
  1743. // since dynamic recipients are dev inputted
  1744. // we aren't going to error on invalid ones
  1745. // but rather just accept if present, and move on if not
  1746. $recipients_list = $this->param('recipients_list');
  1747. $field_out = '';
  1748. foreach($recipients_list as $i => $r_data)
  1749. {
  1750. if (in_array($r_data['key'], $recipient_email_input))
  1751. {
  1752. $recipient_emails[] = $r_data['email'];
  1753. $field_out .= $r_data['name'] . ' <' . $r_data['email'] . '>' . "\n";
  1754. }
  1755. }
  1756. //THE ENGLISH ARE TOO MANY!
  1757. if (count($recipient_emails) > $this->param('recipients_limit'))
  1758. {
  1759. $errors['recipient_email'] = lang('over_recipient_limit');
  1760. }
  1761. //does the user have a recipient_email custom field?
  1762. else if (in_array('recipient_email', $valid_fields))
  1763. {
  1764. $_POST['recipient_email'] = trim($field_out);
  1765. }
  1766. }
  1767. //if there is previous recipient emails
  1768. if (empty($recipient_emails) AND
  1769. ! empty($previous_inputs['hash_stored_data']['recipient_emails']))
  1770. {
  1771. $recipient_emails = $previous_inputs['hash_stored_data']['recipient_emails'];
  1772. }
  1773. }
  1774. // -------------------------------------
  1775. // validate user inputted emails
  1776. // -------------------------------------
  1777. $user_recipient_emails = array();
  1778. if ($this->param('recipient_user_input'))
  1779. {
  1780. $user_recipient_email_input = ee()->input->get_post('recipient_email_user');
  1781. if ( ! in_array($user_recipient_email_input, array(FALSE, ''), TRUE))
  1782. {
  1783. $user_recipient_emails = $this->validate_emails($user_recipient_email_input);
  1784. $user_recipient_emails = $user_recipient_emails['good'];
  1785. //if we are here that means we submitted at least something
  1786. //but nothing passed
  1787. if (empty($user_recipient_emails))
  1788. {
  1789. $errors['recipient_user_input'] = lang('no_valid_recipient_emails');
  1790. }
  1791. else if (count($user_recipient_emails) > $this->param('recipient_user_limit'))
  1792. {
  1793. $errors['recipient_email_user'] = lang('over_recipient_user_limit');
  1794. }
  1795. }
  1796. //if there is previous user recipient emails
  1797. if (empty($user_recipient_emails) AND
  1798. ! empty($previous_inputs['hash_stored_data']['user_recipient_emails']))
  1799. {
  1800. $user_recipient_emails = $previous_inputs['hash_stored_data']['user_recipient_emails'];
  1801. }
  1802. }
  1803. // -------------------------------------
  1804. // validate status
  1805. // -------------------------------------
  1806. //on edit we want this blank.
  1807. $status = ($edit) ? '' : $form_data['default_status'];
  1808. $input_status = ee()->input->post('status', TRUE);
  1809. $param_status = $this->param('status');
  1810. $available_statuses = $this->data->get_form_statuses();
  1811. //user status input
  1812. if ($this->param('allow_status_edit') AND
  1813. $input_status !== FALSE AND
  1814. array_key_exists($input_status, $available_statuses))
  1815. {
  1816. $status = $input_status;
  1817. }
  1818. //status param
  1819. else if ($param_status !== $status AND
  1820. //this will take care of any blanks
  1821. array_key_exists($param_status, $available_statuses))
  1822. {
  1823. $status = $param_status;
  1824. }
  1825. // -------------------------------------
  1826. // validate
  1827. // -------------------------------------
  1828. $field_input_data = array();
  1829. $field_list = array();
  1830. foreach ($form_data['fields'] as $field_id => $field_data)
  1831. {
  1832. $field_list[$field_data['field_name']] = $field_data['field_label'];
  1833. $field_post = ee()->input->post($field_data['field_name'], TRUE);
  1834. //if it's not even in $_POST or $_GET, lets skip input
  1835. //unless its an uploaded file, then we'll send false anyway
  1836. //because its field type will handle the rest of that work
  1837. if ($field_post !== FALSE OR
  1838. isset($_FILES[$field_data['field_name']]))
  1839. {
  1840. $field_input_data[$field_data['field_name']] = $field_post;
  1841. }
  1842. }
  1843. //form fields do their own validation,
  1844. //so lets just get results! (sexy results?)
  1845. $this->field_errors = array_merge(
  1846. $this->field_errors,
  1847. ee()->freeform_fields->validate(
  1848. $form_id,
  1849. $field_input_data,
  1850. ! ($this->is_ajax_request() OR $this->param('inline_errors'))
  1851. )
  1852. );
  1853. // -------------------------------------
  1854. // post validate hook
  1855. // -------------------------------------
  1856. if (ee()->extensions->active_hook('freeform_module_validate_end') === TRUE)
  1857. {
  1858. $backup_errors = $errors;
  1859. $errors = ee()->extensions->universal_call(
  1860. 'freeform_module_validate_end',
  1861. $errors,
  1862. $this
  1863. );
  1864. if (ee()->extensions->end_script === TRUE) return;
  1865. //valid data?
  1866. if ( ! is_array($errors) AND
  1867. $this->check_yes($this->preference('hook_data_protection')))
  1868. {
  1869. $errors = $backup_errors;
  1870. }
  1871. }
  1872. // -------------------------------------
  1873. // captcha
  1874. // -------------------------------------
  1875. if ( ! $validate_only AND
  1876. ee()->input->get_post('validate_only') === FALSE AND
  1877. $last_page AND
  1878. $this->param('require_captcha'))
  1879. {
  1880. if ( trim(ee()->input->post('captcha')) == '')
  1881. {
  1882. $errors[] = lang('captcha_required');
  1883. }
  1884. else
  1885. {
  1886. ee()->db->where('word', ee()->input->post('captcha', TRUE));
  1887. ee()->db->where('ip_address', ee()->input->ip_address());
  1888. ee()->db->where('date > ', '(UNIX_TIMESTAMP()-7200)', FALSE);
  1889. if ( ! ee()->db->count_all_results('captcha'))
  1890. {
  1891. $errors[] = lang('captcha_required');
  1892. }
  1893. ee()->db->where('word', ee()->input->post('captcha', TRUE));
  1894. ee()->db->where('ip_address', ee()->input->ip_address());
  1895. ee()->db->where('date < ', '(UNIX_TIMESTAMP()-7200)', FALSE);
  1896. ee()->db->delete('captcha');
  1897. }
  1898. }
  1899. $all_errors = array_merge($errors, $this->field_errors);
  1900. // -------------------------------------
  1901. // halt on errors
  1902. // -------------------------------------
  1903. if (count($all_errors) > 0)
  1904. {
  1905. // -------------------------------------
  1906. // EE 2.7 auto removes XID so we
  1907. // have to restore it on errors where
  1908. // we want the back button to work.
  1909. // EE 2.8 changes everything again ;D.
  1910. // -------------------------------------
  1911. if (version_compare($this->ee_version, '2.7', '>=') &&
  1912. version_compare($this->ee_version, '2.8', '<'))
  1913. {
  1914. ee()->security->restore_xid();
  1915. }
  1916. // -------------------------------------
  1917. // inline errors
  1918. // -------------------------------------
  1919. if ($this->param('inline_errors'))
  1920. {
  1921. ee()->load->model('freeform_param_model');
  1922. $error_param_id = ee()->freeform_param_model->insert_params(
  1923. array(
  1924. 'general_errors' => $errors,
  1925. 'field_errors' => $this->field_errors,
  1926. 'inputs' => $field_input_data,
  1927. 'stored_data' => array(
  1928. 'recipient_emails' => $recipient_emails,
  1929. 'user_recipient_emails' => $user_recipient_emails
  1930. )
  1931. )
  1932. );
  1933. ee()->session->set_flashdata('freeform_errors', $error_param_id);
  1934. ee()->functions->redirect(
  1935. $this->prep_url(
  1936. $this->param('inline_error_return'),
  1937. $this->param('secure_return')
  1938. )
  1939. );
  1940. return $this->do_exit();
  1941. }
  1942. // -------------------------------------
  1943. // ajax or standard user error
  1944. // -------------------------------------
  1945. $this->actions()->full_stop($all_errors);
  1946. }
  1947. //send ajax response exists
  1948. //but this is in case someone is using a replacer
  1949. //that uses
  1950. if ($validate_only OR ee()->input->get_post('validate_only') !== FALSE)
  1951. {
  1952. if ($this->is_ajax_request())
  1953. {
  1954. $this->restore_xid();
  1955. $this->send_ajax_response(array(
  1956. 'success' => TRUE,
  1957. 'errors' => array()
  1958. ));
  1959. }
  1960. return $this->do_exit();
  1961. }
  1962. // -------------------------------------
  1963. // status
  1964. // -------------------------------------
  1965. //if we have no status (edit or some other weirdness)
  1966. //let the forms lib handle it.
  1967. if ( ! $edit || trim($status) !== '')
  1968. {
  1969. $field_input_data['status'] = $status;
  1970. }
  1971. // -------------------------------------
  1972. // entry insert begin hook
  1973. // -------------------------------------
  1974. if (ee()->extensions->active_hook('freeform_module_insert_begin') === TRUE)
  1975. {
  1976. $backup_data = $field_input_data;
  1977. $field_input_data = ee()->extensions->universal_call(
  1978. 'freeform_module_insert_begin',
  1979. $field_input_data,
  1980. $entry_id,
  1981. $form_id,
  1982. $this
  1983. );
  1984. if (ee()->extensions->end_script === TRUE)
  1985. {
  1986. return;
  1987. }
  1988. // -------------------------------------
  1989. // if some butthead doesn't return
  1990. // the array from their extension
  1991. // we need a backup here or everything
  1992. // busts.
  1993. // -------------------------------------
  1994. if ( ! is_array($field_input_data) AND
  1995. $this->check_yes($this->preference('hook_data_protection')))
  1996. {
  1997. $field_input_data = $backup_data;
  1998. }
  1999. }
  2000. // -------------------------------------
  2001. // insert/update data into db
  2002. // -------------------------------------
  2003. $entry_id = ee()->freeform_forms->insert_new_entry(
  2004. $form_id,
  2005. $field_input_data
  2006. );
  2007. // -------------------------------------
  2008. // entry insert end hook
  2009. // -------------------------------------
  2010. if (ee()->extensions->active_hook('freeform_module_insert_end') === TRUE)
  2011. {
  2012. ee()->extensions->universal_call(
  2013. 'freeform_module_insert_end',
  2014. $field_input_data,
  2015. $entry_id,
  2016. $form_id,
  2017. $this
  2018. );
  2019. if (ee()->extensions->end_script === TRUE)
  2020. {
  2021. return;
  2022. }
  2023. }
  2024. // -------------------------------------
  2025. // delete xid and captcha
  2026. // -------------------------------------
  2027. // wait this late because we dont
  2028. // want to remove before a custom field
  2029. // has a chance to throw an error
  2030. // on one of its actions, like file
  2031. // upload
  2032. // -------------------------------------
  2033. if ($last_page AND $this->param('require_captcha'))
  2034. {
  2035. ee()->db->where(array(
  2036. 'word' => ee()->input->post('captcha'),
  2037. 'ip_address' => ee()->input->ip_address()
  2038. ));
  2039. ee()->db->or_where('date <', ee()->localize->now - 7200);
  2040. ee()->db->delete('captcha');
  2041. }
  2042. if (version_compare($this->ee_version, '2.8', '<') &&
  2043. $this->check_yes(ee()->config->item('secure_forms')) )
  2044. {
  2045. ee()->security->delete_xid(ee()->input->post('XID'));
  2046. }
  2047. // -------------------------------------
  2048. // if we are multipaging and going
  2049. // to the previous page, bail early
  2050. // -------------------------------------
  2051. if ($multipage &&
  2052. $submit_to_previous &&
  2053. $this->param('multipage_previous_page'))
  2054. {
  2055. ee()->functions->redirect(
  2056. $this->prep_url(
  2057. $this->param('multipage_previous_page'),
  2058. $this->param('secure_return')
  2059. )
  2060. );
  2061. return $this->do_exit();
  2062. }
  2063. // -------------------------------------
  2064. // if we are multi-paging, move on
  2065. // -------------------------------------
  2066. if ($multipage AND ! $last_page)
  2067. {
  2068. ee()->functions->redirect(
  2069. $this->prep_url(
  2070. $this->param('multipage_next_page'),
  2071. $this->param('secure_return')
  2072. )
  2073. );
  2074. return $this->do_exit();
  2075. }
  2076. // -------------------------------------
  2077. // edit data for notifications?
  2078. // -------------------------------------
  2079. if ($edit)
  2080. {
  2081. $edit_data = $this->data->get_entry_data_by_id($entry_id, $form_id);
  2082. if (is_array($previous_inputs))
  2083. {
  2084. $previous_inputs = array_merge($edit_data, $previous_inputs);
  2085. }
  2086. else
  2087. {
  2088. $previous_inputs = $edit_data;
  2089. }
  2090. }
  2091. // -------------------------------------
  2092. // previous inputs need their real names
  2093. // -------------------------------------
  2094. foreach ($form_data['fields'] as $field_id => $field_data)
  2095. {
  2096. if (is_array($previous_inputs))
  2097. {
  2098. $fid = ee()->freeform_form_model->form_field_prefix . $field_id;
  2099. //id name? field_id_1, etc
  2100. if (isset($previous_inputs[$fid]))
  2101. {
  2102. $previous_inputs[$field_data['field_name']] = $previous_inputs[$fid];
  2103. }
  2104. }
  2105. }
  2106. $field_input_data = array_merge(
  2107. (is_array($previous_inputs) ? $previous_inputs : array()),
  2108. array('entry_id' => $entry_id),
  2109. $field_input_data
  2110. );
  2111. // -------------------------------------
  2112. // do notifications
  2113. // -------------------------------------
  2114. if ( ! $edit OR $this->param('notify_on_edit'))
  2115. {
  2116. if ($this->param('notify_admin'))
  2117. {
  2118. ee()->freeform_notifications->send_notification(array(
  2119. 'form_id' => $form_id,
  2120. 'entry_id' => $entry_id,
  2121. 'notification_type' => 'admin',
  2122. 'recipients' => $this->param('admin_notify'),
  2123. 'form_input_data' => $field_input_data,
  2124. 'cc_recipients' => $this->param('admin_cc_notify'),
  2125. 'bcc_recipients' => $this->param('admin_bcc_notify'),
  2126. 'template' => $this->param('admin_notification_template')
  2127. ));
  2128. }
  2129. //this is a custom field named by the user
  2130. //notifications does its own validation
  2131. //so if someone puts a non-validated input field
  2132. //then notifications will just silently fail
  2133. //because it wont be a user input problem
  2134. //but rather a dev implementation problem
  2135. if ($this->param('notify_user') AND
  2136. $this->param('user_email_field') AND
  2137. isset($field_input_data[$this->param('user_email_field')]))
  2138. {
  2139. ee()->freeform_notifications->send_notification(array(
  2140. 'form_id' => $form_id,
  2141. 'entry_id' => $entry_id,
  2142. 'notification_type' => 'user',
  2143. 'recipients' => $field_input_data[$this->param('user_email_field')],
  2144. 'form_input_data' => $field_input_data,
  2145. 'template' => $this->param('user_notification_template'),
  2146. 'enable_spam_log' => FALSE
  2147. ));
  2148. }
  2149. //recipients
  2150. if ( ! empty($recipient_emails))
  2151. {
  2152. ee()->freeform_notifications->send_notification(array(
  2153. 'form_id' => $form_id,
  2154. 'entry_id' => $entry_id,
  2155. 'notification_type' => 'user_recipient',
  2156. 'recipients' => $recipient_emails,
  2157. 'form_input_data' => $field_input_data,
  2158. 'template' => $this->param('recipient_template')
  2159. ));
  2160. }
  2161. //user inputted recipients
  2162. if ( ! empty($user_recipient_emails))
  2163. {
  2164. ee()->freeform_notifications->send_notification(array(
  2165. 'form_id' => $form_id,
  2166. 'entry_id' => $entry_id,
  2167. 'notification_type' => 'user_recipient',
  2168. 'recipients' => $user_recipient_emails,
  2169. 'form_input_data' => $field_input_data,
  2170. 'template' => $this->param('recipient_user_template')
  2171. ));
  2172. }
  2173. }
  2174. // -------------------------------------
  2175. // return
  2176. // -------------------------------------
  2177. $return_url = $this->param('return');
  2178. if (ee()->input->post('return') !== FALSE)
  2179. {
  2180. $return_url = ee()->input->post('return');
  2181. }
  2182. $return = str_replace(
  2183. //because. Shut up.
  2184. array(
  2185. '%%form_entry_id%%',
  2186. '%%entry_id%%',
  2187. '%form_entry_id%',
  2188. '%entry_id%'
  2189. ),
  2190. $entry_id,
  2191. $this->prep_url(
  2192. $return_url,
  2193. $this->param('secure_return')
  2194. )
  2195. );
  2196. //detergent?
  2197. if ($this->is_ajax_request())
  2198. {
  2199. $this->send_ajax_response(array(
  2200. 'success' => TRUE,
  2201. 'entry_id' => $entry_id,
  2202. 'form_id' => $form_id,
  2203. 'return' => $return,
  2204. 'return_url' => $return
  2205. ));
  2206. }
  2207. else
  2208. {
  2209. ee()->functions->redirect($return);
  2210. }
  2211. }
  2212. //END save_form
  2213. // --------------------------------------------------------------------
  2214. // private! No looky!
  2215. // --------------------------------------------------------------------
  2216. // --------------------------------------------------------------------
  2217. /**
  2218. * Pre-Validation Errors that are deal breakers
  2219. *
  2220. * @access protected
  2221. * @param mixed $errors error string or array of errors
  2222. * @return null exits
  2223. */
  2224. protected function pre_validation_error($errors)
  2225. {
  2226. // -------------------------------------
  2227. // NOTE: These are pre-validation errors
  2228. // that are only supposed to be things
  2229. // that are fatal to the submitting
  2230. // of the form.
  2231. // -------------------------------------
  2232. if ($this->param('inline_errors'))
  2233. {
  2234. ee()->load->model('freeform_param_model');
  2235. $error_param_id = ee()->freeform_param_model->insert_params(
  2236. array(
  2237. 'general_errors' => is_array($errors) ? $errors : array($errors),
  2238. 'field_errors' => array(),
  2239. 'inputs' => array()
  2240. )
  2241. );
  2242. ee()->session->set_flashdata('freeform_errors', $error_param_id);
  2243. ee()->functions->redirect(
  2244. $this->prep_url(
  2245. $this->param('inline_error_return'),
  2246. $this->param('secure_return')
  2247. )
  2248. );
  2249. return $this->do_exit();
  2250. }
  2251. return $this->actions()->full_stop($errors);
  2252. }
  2253. //END pre_validation_error
  2254. // --------------------------------------------------------------------
  2255. /**
  2256. * build_form
  2257. *
  2258. * builds a form based on passed data
  2259. *
  2260. * @access private
  2261. * @
  2262. * @return mixed boolean false if not found else id
  2263. */
  2264. private function build_form($data)
  2265. {
  2266. // -------------------------------------
  2267. // prep input data
  2268. // -------------------------------------
  2269. //set defaults for optional items
  2270. $input_defaults = array(
  2271. 'action' => '/',
  2272. 'hidden_fields' => array(),
  2273. 'tagdata' => ee()->TMPL->tagdata,
  2274. );
  2275. //array2 overwrites any duplicate key from array1
  2276. $data = array_merge($input_defaults, $data);
  2277. //OK, so form_open is supposed to be doing this,
  2278. //but guess what: It only works if CI sees that
  2279. //config->item('csrf_protection') === true, and uh
  2280. //sometimes it's false eventhough secure_forms == 'y'
  2281. //
  2282. if ( $this->check_yes(ee()->config->item('secure_forms')) )
  2283. {
  2284. $data['hidden_fields'][$this->sc->csrf_name] = $this->create_xid();
  2285. }
  2286. // --------------------------------------------
  2287. // HTTPS URLs?
  2288. // --------------------------------------------
  2289. $data['action'] = $this->prep_url(
  2290. $data['action'],
  2291. (
  2292. isset($this->params['secure_action']) AND
  2293. $this->params['secure_action']
  2294. )
  2295. );
  2296. foreach(array('return', 'RET') as $return_field)
  2297. {
  2298. if (isset($data['hidden_fields'][$return_field]))
  2299. {
  2300. $data['hidden_fields'][$return_field] = $this->prep_url(
  2301. $data['hidden_fields'][$return_field],
  2302. (
  2303. isset($this->params['secure_return']) AND
  2304. $this->params['secure_return']
  2305. )
  2306. );
  2307. }
  2308. }
  2309. // --------------------------------------------
  2310. // Override Form Attributes with form:xxx="" parameters
  2311. // --------------------------------------------
  2312. $form_attributes = array();
  2313. if (is_object(ee()->TMPL) AND ! empty(ee()->TMPL->tagparams))
  2314. {
  2315. foreach(ee()->TMPL->tagparams as $key => $value)
  2316. {
  2317. if (strncmp($key, 'form:', 5) == 0)
  2318. {
  2319. //allow action override.
  2320. if (substr($key, 5) == 'action')
  2321. {
  2322. $data['action'] = $value;
  2323. }
  2324. else
  2325. {
  2326. $form_attributes[substr($key, 5)] = $value;
  2327. }
  2328. }
  2329. }
  2330. }
  2331. // --------------------------------------------
  2332. // Create and Return Form
  2333. // --------------------------------------------
  2334. //have to have this for file uploads
  2335. if ($this->multipart)
  2336. {
  2337. $form_attributes['enctype'] = 'multipart/form-data';
  2338. }
  2339. $form_attributes['method'] = $data['method'];
  2340. $return = form_open(
  2341. $data['action'],
  2342. $form_attributes,
  2343. $data['hidden_fields']
  2344. );
  2345. //Rremoved stripslashes as it was affecting html5 regex
  2346. //validation and no one can really remember why it was
  2347. //here in the first place (since FF 1.x). Might be that
  2348. //it was a legacy thing with EE 1.x.
  2349. //$return .= stripslashes($data['tagdata']);
  2350. $return .= $data['tagdata'];
  2351. $return .= "</form>";
  2352. return $return;
  2353. }
  2354. //END build_form
  2355. // --------------------------------------------------------------------
  2356. /**
  2357. * form_id - finds form id the best it can
  2358. *
  2359. * @access private
  2360. * @param bool $allow_multiple allow multiple input?
  2361. * @return mixed boolean false if not found else id
  2362. */
  2363. private function form_id($allow_multiple = FALSE, $use_cache = TRUE)
  2364. {
  2365. if ($use_cache AND $this->form_id)
  2366. {
  2367. return $this->form_id;
  2368. }
  2369. $form_id = FALSE;
  2370. $possible_name = FALSE;
  2371. $possible_label = FALSE;
  2372. $possible_id = FALSE;
  2373. $tmpl_available = (isset(ee()->TMPL) AND is_object(ee()->TMPL));
  2374. // -------------------------------------
  2375. // by direct param first
  2376. // -------------------------------------
  2377. if ($tmpl_available)
  2378. {
  2379. $possible_id = ee()->TMPL->fetch_param('form_id');
  2380. }
  2381. // -------------------------------------
  2382. // by name param
  2383. // -------------------------------------
  2384. if ( ! $possible_id AND $tmpl_available)
  2385. {
  2386. $possible_name = ee()->TMPL->fetch_param('form_name');
  2387. }
  2388. // -------------------------------------
  2389. // by label (with legacy for collection)
  2390. // -------------------------------------
  2391. if ($tmpl_available AND ! $possible_id AND ! $possible_name)
  2392. {
  2393. $possible_label = ee()->TMPL->fetch_param('form_label');
  2394. if ( ! $possible_label)
  2395. {
  2396. $possible_label = ee()->TMPL->fetch_param('collection');
  2397. }
  2398. }
  2399. // -------------------------------------
  2400. // params id
  2401. // -------------------------------------
  2402. if ( ! $possible_id AND
  2403. ! $possible_name AND
  2404. ! $possible_label AND
  2405. $this->param('form_id'))
  2406. {
  2407. $possible_id = $this->param('form_id');
  2408. }
  2409. // -------------------------------------
  2410. // params name
  2411. // -------------------------------------
  2412. if ( ! $possible_id AND
  2413. ! $possible_name AND
  2414. ! $possible_label AND
  2415. $this->param('form_name'))
  2416. {
  2417. $possible_name = $this->param('form_name');
  2418. }
  2419. // -------------------------------------
  2420. // get post id
  2421. // -------------------------------------
  2422. if ( ! $possible_id AND
  2423. ! $possible_name AND
  2424. ! $possible_label)
  2425. {
  2426. $possible_id = ee()->input->get_post('form_id');
  2427. }
  2428. // -------------------------------------
  2429. // get post name
  2430. // -------------------------------------
  2431. if ( ! $possible_id AND
  2432. ! $possible_name AND
  2433. ! $possible_label)
  2434. {
  2435. $possible_name = ee()->input->get_post('form_name');
  2436. }
  2437. // -------------------------------------
  2438. // check possibles
  2439. // -------------------------------------
  2440. if ($possible_id)
  2441. {
  2442. //if multiple and match pattern...
  2443. if ($allow_multiple AND preg_match('/^[\d\|]+$/', $possible_id))
  2444. {
  2445. $ids = $this->actions()->pipe_split($possible_id);
  2446. ee()->load->model('freeform_form_model');
  2447. $result = ee()->freeform_form_model->select('form_id')
  2448. ->get(array('form_id' => $ids));
  2449. //we only want results, not everything
  2450. if ($result !== FALSE)
  2451. {
  2452. $form_id = array();
  2453. foreach ($result as $row)
  2454. {
  2455. $form_id[] = $row['form_id'];
  2456. }
  2457. }
  2458. }
  2459. else if ($this->is_positive_intlike($possible_id) AND
  2460. $this->data->is_valid_form_id($possible_id))
  2461. {
  2462. $form_id = $possible_id;
  2463. }
  2464. }
  2465. if ( ! $form_id AND $possible_name)
  2466. {
  2467. //if multiple and pipe
  2468. if ($allow_multiple AND stristr($possible_name, '|'))
  2469. {
  2470. $names = $this->actions()->pipe_split($possible_name);
  2471. ee()->load->model('freeform_form_model');
  2472. $result = ee()->freeform_form_model->select('form_id')
  2473. ->get(array('form_name' => $names));
  2474. //we only want results, not everything
  2475. if ($result !== FALSE)
  2476. {
  2477. $form_id = array();
  2478. foreach ($result as $row)
  2479. {
  2480. $form_id[] = $row['form_id'];
  2481. }
  2482. }
  2483. }
  2484. else
  2485. {
  2486. $possible_id = $this->data->get_form_id_by_name($possible_name);
  2487. if ($possible_id !== FALSE AND $possible_id > 0)
  2488. {
  2489. $form_id = $possible_id;
  2490. }
  2491. }
  2492. }
  2493. if ( ! $form_id AND $possible_label)
  2494. {
  2495. ee()->load->model('freeform_form_model');
  2496. //if multiple and pipe
  2497. if ($allow_multiple AND stristr($possible_label, '|'))
  2498. {
  2499. $names = $this->actions()->pipe_split($possible_label);
  2500. $result = ee()->freeform_form_model
  2501. ->select('form_id')
  2502. ->get(array('form_label' => $names));
  2503. //we only want results, not everything
  2504. if ($result !== FALSE)
  2505. {
  2506. $form_id = array();
  2507. foreach ($result as $row)
  2508. {
  2509. $form_id[] = $row['form_id'];
  2510. }
  2511. }
  2512. }
  2513. else
  2514. {
  2515. $possible_id = ee()->freeform_form_model
  2516. ->select('form_id')
  2517. ->get_row(array('form_label' => $possible_label));
  2518. if ($possible_id !== FALSE)
  2519. {
  2520. $form_id = $possible_id['form_id'];
  2521. }
  2522. }
  2523. }
  2524. // -------------------------------------
  2525. // store if good
  2526. // -------------------------------------
  2527. if ($form_id AND $form_id > 0)
  2528. {
  2529. $this->form_id = $form_id;
  2530. }
  2531. return $form_id;
  2532. }
  2533. //END form_id
  2534. // --------------------------------------------------------------------
  2535. /**
  2536. * entry_id - finds entry id the best it can
  2537. *
  2538. * @access private
  2539. * @return mixed boolean false if not found else id
  2540. */
  2541. private function entry_id()
  2542. {
  2543. $form_id = $this->form_id();
  2544. if ( ! $form_id)
  2545. {
  2546. return FALSE;
  2547. }
  2548. if (isset($this->entry_id) AND $this->entry_id)
  2549. {
  2550. return $this->entry_id;
  2551. }
  2552. $entry_id = FALSE;
  2553. // -------------------------------------
  2554. // by direct param first
  2555. // -------------------------------------
  2556. if (isset(ee()->TMPL) AND is_object(ee()->TMPL))
  2557. {
  2558. $entry_id_param = ee()->TMPL->fetch_param('entry_id');
  2559. if ( $this->is_positive_intlike($entry_id_param) AND
  2560. $this->data->is_valid_entry_id($entry_id_param, $form_id))
  2561. {
  2562. $entry_id = $entry_id_param;
  2563. }
  2564. }
  2565. // -------------------------------------
  2566. // params id
  2567. // -------------------------------------
  2568. if ( ! $entry_id AND $this->param('entry_id'))
  2569. {
  2570. $entry_id_param = $this->param('entry_id');
  2571. if ( $this->is_positive_intlike($entry_id_param) AND
  2572. $this->data->is_valid_entry_id($entry_id_param, $form_id))
  2573. {
  2574. $entry_id = $entry_id_param;
  2575. }
  2576. }
  2577. // -------------------------------------
  2578. // get post id
  2579. // -------------------------------------
  2580. if ( ! $entry_id AND ee()->input->get_post('entry_id'))
  2581. {
  2582. $entry_id_param = ee()->input->get_post('entry_id');
  2583. if ( $this->is_positive_intlike($entry_id_param) AND
  2584. $this->data->is_valid_entry_id($entry_id_param, $form_id))
  2585. {
  2586. $entry_id = $entry_id_param;
  2587. }
  2588. }
  2589. // -------------------------------------
  2590. // store if good
  2591. // -------------------------------------
  2592. if ($entry_id AND $entry_id > 0)
  2593. {
  2594. $this->entry_id = $entry_id;
  2595. }
  2596. return $entry_id;
  2597. }
  2598. //END entry_id
  2599. // --------------------------------------------------------------------
  2600. /**
  2601. * Set Form Params
  2602. *
  2603. * @access public
  2604. * @param array incoming form data for defaults
  2605. * @param bool rerun param finding?
  2606. * @return array array of params found
  2607. */
  2608. public function set_form_params($rerun = FALSE)
  2609. {
  2610. if ( ! $rerun && $this->params_ran)
  2611. {
  2612. return $this->params;
  2613. }
  2614. $params_with_defaults = $this->get_default_params();
  2615. foreach ($params_with_defaults as $name => $default)
  2616. {
  2617. $this->set_form_param($name);
  2618. }
  2619. //we use the bool here because
  2620. //the params array can have items set to it
  2621. //outside of the defaults running here
  2622. $this->params_ran = true;
  2623. return $this->params;
  2624. }
  2625. //set_form_params
  2626. // --------------------------------------------------------------------
  2627. /**
  2628. * Set Form Param
  2629. *
  2630. * @access public
  2631. * @param string $name name of param
  2632. * @param mixed $value optional value to set param to
  2633. * @param boolean $set_tagparam [description]
  2634. */
  2635. public function set_form_param($name, $value = null, $set_tagparam = false)
  2636. {
  2637. $params_with_defaults = $this->get_default_params();
  2638. //not default? lets just set it.
  2639. if ( ! isset($params_with_defaults[$name]))
  2640. {
  2641. if ($value === null)
  2642. {
  2643. $value = ee()->TMPL->fetch_param($name);
  2644. }
  2645. $this->params[$name] = $value;
  2646. }
  2647. else
  2648. {
  2649. $default = $params_with_defaults[$name];
  2650. //if the default is a boolean value we only want a boolean
  2651. //output
  2652. if (is_bool($default))
  2653. {
  2654. if ($value === null)
  2655. {
  2656. $value = ee()->TMPL->fetch_param($name);
  2657. }
  2658. //and if there is a string version of the param
  2659. if (is_string($value))
  2660. {
  2661. //and if the default is boolean true
  2662. if ($default === TRUE)
  2663. {
  2664. //and if the template param uses an indicator of the
  2665. //'false' variety, we want to override the default
  2666. //of TRUE and set FALSE.
  2667. $this->params[$name] = ! $this->check_no($value);
  2668. }
  2669. //but if the default is boolean false
  2670. else
  2671. {
  2672. //and the template param is trying to turn the feature
  2673. //on through a 'y', 'yes', or 'on' value, then we want
  2674. //to convert the FALSE to a TRUE
  2675. $this->params[$name] = $this->check_yes($value);
  2676. }
  2677. }
  2678. //there is no template param version of
  2679. //this default so the default stands
  2680. else
  2681. {
  2682. //for setting tagparam, however rare
  2683. $value = $default;
  2684. $this->params[$name] = $default;
  2685. }
  2686. }
  2687. //other wise check for the param or fallback on default
  2688. else
  2689. {
  2690. if ($value === null)
  2691. {
  2692. $value = trim(
  2693. ee()->TMPL->fetch_param($name, $default)
  2694. );
  2695. }
  2696. $this->params[$name] = $value;
  2697. }
  2698. }
  2699. if ($set_tagparam && $value !== null)
  2700. {
  2701. ee()->TMPL->tagparams[$name] = $value;
  2702. }
  2703. }
  2704. //END set_form_param
  2705. // --------------------------------------------------------------------
  2706. /**
  2707. * Get Default Params
  2708. *
  2709. * Gets default Params and sets them to class var if not alraedy set
  2710. * @access public
  2711. * @return array key value array of default params
  2712. */
  2713. public function get_default_params()
  2714. {
  2715. if (isset($this->params_with_defaults))
  2716. {
  2717. return $this->params_with_defaults;
  2718. }
  2719. if ( ! isset($this->form_data))
  2720. {
  2721. $this->form_data = $this->data->get_form_info($this->form_id());
  2722. }
  2723. $this->params_with_defaults = array(
  2724. //security
  2725. 'secure_action' => FALSE,
  2726. 'secure_return' => FALSE,
  2727. 'require_captcha' => $this->require_captcha(),
  2728. 'require_ip' => ! $this->check_no(
  2729. ee()->config->item("require_ip_for_posting")
  2730. ),
  2731. 'return' => ee()->uri->uri_string,
  2732. 'inline_error_return' => ee()->uri->uri_string,
  2733. 'error_page' => '',
  2734. 'ajax' => TRUE,
  2735. 'restrict_edit_to_author' => TRUE,
  2736. 'inline_errors' => FALSE,
  2737. //dupe prevention
  2738. 'prevent_duplicate_on' => '',
  2739. 'prevent_duplicate_per_site' => FALSE,
  2740. 'secure_duplicate_redirect' => FALSE,
  2741. 'duplicate_redirect' => '',
  2742. 'error_on_duplicate' => FALSE,
  2743. //required or matching fields
  2744. 'required' => '',
  2745. 'matching_fields' => '',
  2746. //multipage
  2747. 'last_page' => TRUE,
  2748. 'multipage' => FALSE,
  2749. 'redirect_on_timeout' => TRUE,
  2750. 'redirect_on_timeout_to' => '',
  2751. 'page_marker' => $this->default_mp_page_marker,
  2752. 'multipage_page' => '',
  2753. 'paging_url' => '',
  2754. 'multipage_page_names' => '',
  2755. //notifications
  2756. 'admin_notify' => $this->form_data['admin_notification_email'],
  2757. 'admin_cc_notify' => '',
  2758. 'admin_bcc_notify' => '',
  2759. 'notify_user' => $this->check_yes($this->form_data['notify_user']),
  2760. 'notify_admin' => $this->check_yes($this->form_data['notify_admin']),
  2761. 'notify_on_edit' => FALSE,
  2762. 'user_email_field' => $this->form_data['user_email_field'],
  2763. //dynamic_recipients
  2764. 'recipients' => FALSE,
  2765. 'recipients_limit' => '3',
  2766. //user inputted recipients
  2767. 'recipient_user_input' => FALSE,
  2768. 'recipient_user_limit' => '3',
  2769. //templates
  2770. 'recipient_template' => "",
  2771. 'recipient_user_template' => "",
  2772. 'admin_notification_template' => $this->form_data['admin_notification_id'],
  2773. 'user_notification_template' => $this->form_data['user_notification_id'],
  2774. //we already set default status in like 5 places
  2775. 'status' => '',//$this->form_data['default_status'],
  2776. 'allow_status_edit' => FALSE,
  2777. );
  2778. return $this->params_with_defaults;
  2779. }
  2780. //END get_default_params
  2781. // --------------------------------------------------------------------
  2782. /**
  2783. * Require Captcha?
  2784. *
  2785. * @access public
  2786. * @return boolean user isn't logged in or member require captcha
  2787. */
  2788. public function require_captcha()
  2789. {
  2790. return (
  2791. ee()->session->userdata('member_id') == 0 OR
  2792. $this->check_yes(ee()->config->item('captcha_require_members'))
  2793. );
  2794. }
  2795. //END require_captcha
  2796. // --------------------------------------------------------------------
  2797. /**
  2798. * Set Page Positions
  2799. *
  2800. * @access public
  2801. * @return array array of page positions for current page
  2802. */
  2803. public function set_page_positions()
  2804. {
  2805. if (isset($this->page_positions))
  2806. {
  2807. return $this->page_positions;
  2808. }
  2809. // -------------------------------------
  2810. // need form params
  2811. // -------------------------------------
  2812. $this->set_form_params();
  2813. // -------------------------------------
  2814. // defaults
  2815. // -------------------------------------
  2816. $current_page = 0;
  2817. $next_page = 0;
  2818. $previous_page = 0;
  2819. $page_type = 'int';
  2820. $page_total = 1;
  2821. // -------------------------------------
  2822. // page array?
  2823. // -------------------------------------
  2824. $mp_page_array = $this->get_mp_page_array();
  2825. // -------------------------------------
  2826. // parse
  2827. // -------------------------------------
  2828. if ( ! empty($mp_page_array))
  2829. {
  2830. $page_type = 'text';
  2831. $position = array_search(
  2832. $this->params['multipage_page'],
  2833. $mp_page_array
  2834. );
  2835. if (in_array($position, array(-1, FALSE), TRUE))
  2836. {
  2837. $position = 0;
  2838. }
  2839. //this will be our human readable
  2840. $current_page = $position + 1;
  2841. $page_total = count($mp_page_array);
  2842. $next_page = ($position + 1 < $page_total) ?
  2843. $mp_page_array[$position + 1] : 0;
  2844. $previous_page = ($position - 1 >= 0) ?
  2845. $mp_page_array[$position - 1] : 0;
  2846. // -------------------------------------
  2847. // set paging url
  2848. // -------------------------------------
  2849. if ($this->params['paging_url'] == '')
  2850. {
  2851. $matches = array();
  2852. if ($this->params['multipage_page'])
  2853. {
  2854. //we want to match all and get the last
  2855. preg_match_all(
  2856. '/(?:\/|^)(' .
  2857. preg_quote($this->params['multipage_page'], '/') .
  2858. ')(?:\/|$)/',
  2859. ee()->uri->uri_string,
  2860. $matches,
  2861. PREG_SET_ORDER
  2862. );
  2863. }
  2864. $match = array();
  2865. if ($matches)
  2866. {
  2867. $match = array_pop($matches);
  2868. }
  2869. if (isset($match[1]))
  2870. {
  2871. $segs = explode('/', ee()->uri->uri_string);
  2872. $i = count($segs);
  2873. while ($i--)
  2874. {
  2875. if ($segs[$i] == $match[1])
  2876. {
  2877. $segs[$i] = '%page%';
  2878. break;
  2879. }
  2880. }
  2881. $this->params['paging_url'] = implode($segs, '/');
  2882. //if they didn't set a redirect on timeout
  2883. //we can assume its this same setup, but with
  2884. //page1 instead of page whatever else.
  2885. if ($this->params['redirect_on_timeout_to'] == '')
  2886. {
  2887. //swap the number from the match, then swap the match
  2888. $this->params['redirect_on_timeout_to'] = str_replace(
  2889. '%page%',
  2890. $mp_page_array[0],
  2891. $this->params['paging_url']
  2892. );
  2893. }
  2894. }
  2895. //END if (isset($match[1]))
  2896. }
  2897. //END if ($this->params['paging_url'] == '')
  2898. }
  2899. //else to if ( ! empty($mp_page_array))
  2900. //manually passed integer?
  2901. else if ($this->params['multipage_page'] != '')
  2902. {
  2903. //remove the marker in case someone sends us a segment
  2904. //with the marker in it like "page2"
  2905. $multipage_page = trim(
  2906. str_replace(
  2907. $this->params['page_marker'],
  2908. '',
  2909. $this->params['multipage_page']
  2910. )
  2911. );
  2912. if ($multipage_page AND
  2913. $this->is_positive_intlike($multipage_page))
  2914. {
  2915. $current_page = $multipage_page;
  2916. $next_page = ($current_page < $page_total) ?
  2917. $current_page + 1 : 0;
  2918. $previous_page = ($current_page > 1) ?
  2919. $current_page - 1 : 0;
  2920. }
  2921. }
  2922. //END if ( ! empty($mp_page_array))
  2923. //else if ($this->params['multipage_page'] != '')
  2924. // -------------------------------------
  2925. // find dynamically?
  2926. // -------------------------------------
  2927. if ($current_page == 0)
  2928. {
  2929. $pm = $this->params['page_marker'];
  2930. //find the page number in /ee/template/page1/
  2931. preg_match(
  2932. '/(?:\/|^)' . preg_quote($pm, '/') . '([0-9]+)(?:\/|$)/',
  2933. ee()->uri->uri_string,
  2934. $matches
  2935. );
  2936. if (isset($matches[1]))
  2937. {
  2938. $current_page = $matches[1];
  2939. //swap the number from the match, then swap the match
  2940. $this->params['paging_url'] = str_replace(
  2941. $pm . $matches[1],
  2942. '%page%',
  2943. ee()->uri->uri_string
  2944. );
  2945. //if they didn't set a redirect on timeout
  2946. //we can assume its this same setup, but with
  2947. //page1 instead of page whatever else.
  2948. if ($this->params['redirect_on_timeout_to'] == '')
  2949. {
  2950. //swap the number from the match, then swap the match
  2951. $this->params['redirect_on_timeout_to'] = str_replace(
  2952. $matches[0],
  2953. str_replace(
  2954. $matches[1],
  2955. '1',
  2956. $matches[0]
  2957. ),
  2958. ee()->uri->uri_string
  2959. );
  2960. }
  2961. }
  2962. }
  2963. //if none of that crap worked, page 1
  2964. if ($current_page == 0)
  2965. {
  2966. $current_page = 1;
  2967. $next_page = ($current_page < $page_total) ?
  2968. $current_page + 1 : 0;
  2969. $previous_page = ($current_page > 1) ?
  2970. $current_page - 1 : 0;
  2971. }
  2972. $this->page_positions = array(
  2973. 'page_type' => $page_type,
  2974. 'current_page' => $current_page,
  2975. 'page_total' => $page_total,
  2976. 'next_page' => $next_page,
  2977. 'previous_page' => $previous_page,
  2978. );
  2979. return $this->page_positions;
  2980. }
  2981. //END set_page_positions
  2982. // --------------------------------------------------------------------
  2983. /**
  2984. * Get Multipage page array
  2985. *
  2986. * @access public
  2987. * @return array array of multipage pages or empty array
  2988. */
  2989. public function get_mp_page_array()
  2990. {
  2991. if (isset($this->mp_page_array))
  2992. {
  2993. return $this->mp_page_array;
  2994. }
  2995. $this->set_form_params();
  2996. if ($this->params['multipage_page_names'] != '')
  2997. {
  2998. $mp_page_array = $this->actions()->pipe_split(
  2999. $this->params['multipage_page_names']
  3000. );
  3001. array_walk($mp_page_array, 'trim');
  3002. $this->mp_page_array = $mp_page_array;
  3003. // -------------------------------------
  3004. // multipage page missing?
  3005. // -------------------------------------
  3006. if ( ! $this->params['multipage_page'])
  3007. {
  3008. foreach ($mp_page_array as $key => $page)
  3009. {
  3010. $mp_page_array[$key] = preg_quote($page, '/');
  3011. }
  3012. $match_string = '/(?:\/|^)(' .
  3013. implode('|', $mp_page_array) .
  3014. ')(?:\/|$)/';
  3015. //we want to match all and get the last
  3016. preg_match_all(
  3017. $match_string,
  3018. ee()->uri->uri_string,
  3019. $matches,
  3020. PREG_SET_ORDER
  3021. );
  3022. if ($matches)
  3023. {
  3024. $match = array_pop($matches);
  3025. if ( ! $this->params['multipage_page'])
  3026. {
  3027. $this->params['multipage_page'] = $match[1];
  3028. }
  3029. }
  3030. }
  3031. }
  3032. else
  3033. {
  3034. $this->mp_page_array = array();
  3035. }
  3036. return $this->mp_page_array;
  3037. }
  3038. //END get_mp_page_array
  3039. // --------------------------------------------------------------------
  3040. /**
  3041. * param - gets stored paramaters
  3042. *
  3043. * @access private
  3044. * @param string $which which param needed
  3045. * @param string $type type of param
  3046. * @return bool $which was empty
  3047. */
  3048. private function param($which = '', $type = 'all')
  3049. {
  3050. // ----------------------------------------
  3051. // Params set?
  3052. // ----------------------------------------
  3053. if ( count( $this->params ) == 0 )
  3054. {
  3055. ee()->load->model('freeform_param_model');
  3056. // ----------------------------------------
  3057. // Empty id?
  3058. // ----------------------------------------
  3059. $params_id = ee()->input->get_post('params_id', TRUE);
  3060. if ( ! $this->is_positive_intlike($params_id) )
  3061. {
  3062. return FALSE;
  3063. }
  3064. $this->params_id = $params_id;
  3065. // -------------------------------------
  3066. // pre-clean so cache can keep
  3067. // -------------------------------------
  3068. ee()->freeform_param_model->cleanup();
  3069. // ----------------------------------------
  3070. // Select from DB
  3071. // ----------------------------------------
  3072. $data = ee()->freeform_param_model->select('data')
  3073. ->get_row($this->params_id);
  3074. // ----------------------------------------
  3075. // Empty?
  3076. // ----------------------------------------
  3077. if ( ! $data )
  3078. {
  3079. return FALSE;
  3080. }
  3081. // ----------------------------------------
  3082. // Unserialize
  3083. // ----------------------------------------
  3084. $this->params = json_decode( $data['data'], TRUE );
  3085. $this->params = is_array($this->params) ? $this->params : array();
  3086. $this->params['set'] = TRUE;
  3087. }
  3088. //END if ( count( $this->params ) == 0 )
  3089. // ----------------------------------------
  3090. // Fetch from params array
  3091. // ----------------------------------------
  3092. if ( isset( $this->params[$which] ) )
  3093. {
  3094. $return = str_replace( "&#47;", "/", $this->params[$which] );
  3095. return $return;
  3096. }
  3097. // ----------------------------------------
  3098. // Fetch TMPL
  3099. // ----------------------------------------
  3100. if ( isset( ee()->TMPL ) AND
  3101. is_object(ee()->TMPL) AND
  3102. ee()->TMPL->fetch_param($which) )
  3103. {
  3104. return ee()->TMPL->fetch_param($which);
  3105. }
  3106. // ----------------------------------------
  3107. // Return (if which is blank, we are just getting data)
  3108. // else if we are looking for something that doesn't exist...
  3109. // ----------------------------------------
  3110. return ($which === '');
  3111. }
  3112. //End param
  3113. // --------------------------------------------------------------------
  3114. /**
  3115. * insert_params - adds multiple params to stored params
  3116. *
  3117. * @access private
  3118. * @param array $param sassociative array of params to send
  3119. * @return mixed insert id or false
  3120. */
  3121. private function insert_params( $params = array() )
  3122. {
  3123. ee()->load->model('freeform_param_model');
  3124. if (empty($params) AND isset($this->params))
  3125. {
  3126. $params = $this->params;
  3127. }
  3128. return ee()->freeform_param_model->insert_params($params);
  3129. }
  3130. // End insert params
  3131. // --------------------------------------------------------------------
  3132. /**
  3133. * prep_url
  3134. *
  3135. * checks a url for {path} or url creation needs with https replacement
  3136. *
  3137. * @access private
  3138. * @param string url to be prepped
  3139. * @param bool replace http with https?
  3140. * @return string url prepped with https or not
  3141. */
  3142. private function prep_url($url, $https = FALSE)
  3143. {
  3144. $return = trim($url);
  3145. $return = ($return !== '') ? $return : ee()->config->item('site_url');
  3146. if ( preg_match( "/".LD."\s*path=(.*?)".RD."/", $return, $match ) > 0 )
  3147. {
  3148. $return = ee()->functions->create_url( $match['1'] );
  3149. }
  3150. else if ( ! preg_match('/^http[s]?:\/\/|^\/\//', $return) )
  3151. {
  3152. $return = ee()->functions->create_url( $return );
  3153. }
  3154. if ($https)
  3155. {
  3156. $return = preg_replace('/^http:\/\/|^\/\//', 'https://', $return);
  3157. }
  3158. return $return;
  3159. }
  3160. //end prep_url
  3161. // --------------------------------------------------------------------
  3162. /**
  3163. * nation ban check
  3164. *
  3165. * sessions built in nation ban check doesn't properly
  3166. * return a bool if show errors are off
  3167. * and we want ajax responses with this
  3168. *
  3169. * @access private
  3170. * @param bool show fatal errors instead of returning bool true
  3171. * @return bool is banned or now
  3172. */
  3173. private function nation_ban_check($show_error = TRUE)
  3174. {
  3175. if ( ! $this->check_yes(ee()->config->item('require_ip_for_posting')) OR
  3176. ! $this->check_yes(ee()->config->item('ip2nation')) OR
  3177. ! ee()->db->table_exists('exp_ip2nation'))
  3178. {
  3179. return FALSE;
  3180. }
  3181. //2.5.2 has a different table and ipv6 support
  3182. if (version_compare($this->ee_version, '2.5.2', '<='))
  3183. {
  3184. ee()->db->select("country");
  3185. ee()->db->where('ip <', ip2long(ee()->input->ip_address()));
  3186. ee()->db->order_by('ip', 'desc');
  3187. $query = ee()->db->get('ip2nation', 1);
  3188. }
  3189. else
  3190. {
  3191. // all IPv4 go to IPv6 mapped
  3192. $addr = ee()->input->ip_address();
  3193. if (strpos($addr, ':') === FALSE &&
  3194. strpos($addr, '.') !== FALSE)
  3195. {
  3196. $addr = '::'.$addr;
  3197. }
  3198. $addr = inet_pton($addr);
  3199. $addr = ee()->db->escape_str($addr);
  3200. $query = ee()->db
  3201. ->select('country')
  3202. ->where("ip_range_low <= '{$addr}'", '', FALSE)
  3203. ->where("ip_range_high >= '{$addr}'", '', FALSE)
  3204. ->order_by('ip_range_low', 'desc')
  3205. ->limit(1, 0)
  3206. ->get('ip2nation');
  3207. }
  3208. if ($query->num_rows() == 1)
  3209. {
  3210. $ip2_query = ee()->db->get_where(
  3211. 'ip2nation_countries',
  3212. array(
  3213. 'code' => $query->row('country'),
  3214. 'banned' => 'y'
  3215. )
  3216. );
  3217. if ($ip2_query->num_rows() > 0)
  3218. {
  3219. if ($show_error == TRUE)
  3220. {
  3221. return ee()->output->fatal_error(
  3222. ee()->config->item('ban_message'),
  3223. 0
  3224. );
  3225. }
  3226. else
  3227. {
  3228. return TRUE;
  3229. }
  3230. }
  3231. }
  3232. return FALSE;
  3233. }
  3234. //END nation_ban_check
  3235. // --------------------------------------------------------------------
  3236. /**
  3237. * Parse Numeric Array Param
  3238. *
  3239. * checks template param for item like 'not 1|2|3'
  3240. *
  3241. * @access private
  3242. * @param string name of param to parse
  3243. * @return mixed false if not set, array if set
  3244. */
  3245. private function parse_numeric_array_param($name = '')
  3246. {
  3247. $return = array();
  3248. if (trim($name) == '')
  3249. {
  3250. return FALSE;
  3251. }
  3252. $name_id = ee()->TMPL->fetch_param($name);
  3253. if ($name_id == FALSE)
  3254. {
  3255. return FALSE;
  3256. }
  3257. $name_id = trim(strtolower($name_id));
  3258. $not = FALSE;
  3259. if (substr($name_id, 0, 3) == 'not')
  3260. {
  3261. $not = TRUE;
  3262. $name_id = preg_replace('/^not[\s]*/', '', $name_id);
  3263. }
  3264. $clean_ids = array();
  3265. if ($name_id !== '')
  3266. {
  3267. $name_id = str_replace(
  3268. 'CURRENT_USER',
  3269. ee()->session->userdata('member_id'),
  3270. $name_id
  3271. );
  3272. if (stristr($name_id, '|'))
  3273. {
  3274. $name_id = $this->actions()->pipe_split($name_id);
  3275. }
  3276. if ( ! is_array($name_id))
  3277. {
  3278. $name_id = array($name_id);
  3279. }
  3280. foreach ($name_id as $value)
  3281. {
  3282. $value = trim($value);
  3283. if ($this->is_positive_intlike($value))
  3284. {
  3285. $clean_ids[] = $value;
  3286. }
  3287. }
  3288. }
  3289. return array(
  3290. 'not' => $not,
  3291. 'ids' => $clean_ids
  3292. );
  3293. }
  3294. //END parse_numeric_array_param
  3295. // --------------------------------------------------------------------
  3296. /**
  3297. * Tag Prefix replace
  3298. *
  3299. * Takes a set of tags and removes unprefixed tags then removes the
  3300. * prefixes from the prefixed ones. Sending reverse true re-instates the
  3301. * unprefixed items
  3302. *
  3303. * @param string $prefix prefix for tags
  3304. * @param array $tags array of tags to look for prefixes with
  3305. * @param string $tagdata incoming tagdata to replace on
  3306. * @param boolean $reverse reverse the replacements?
  3307. * @return string tagdata with replacements
  3308. */
  3309. public function tag_prefix_replace($prefix = '', $tags = array(),
  3310. $tagdata = '', $reverse = FALSE)
  3311. {
  3312. if ($prefix == '' OR ! is_array($tags) OR empty($tags))
  3313. {
  3314. return $tagdata;
  3315. }
  3316. //allowing ':' in a prefix
  3317. if (substr($prefix, -1, 1) !== ':')
  3318. {
  3319. $prefix = rtrim($prefix, '_') . '_';
  3320. }
  3321. $hash = '02be645684a54f45f08d0b1dbadf78e1a3a9f2ee';
  3322. $find = array();
  3323. $hash_replace = array();
  3324. $prefix_replace = array();
  3325. $length = count($tags);
  3326. foreach ($tags as $key => $item)
  3327. {
  3328. $nkey = $key + $length;
  3329. //if there is nothing prefixed, we don't want to do anything datastardly
  3330. if ( ! $reverse AND
  3331. strpos($tagdata, LD . $prefix . $item) === FALSE)
  3332. {
  3333. continue;
  3334. }
  3335. //this is terse, but it ensures that we
  3336. //find any an all tag pairs if they occur
  3337. $find[$key] = $item;
  3338. $find[$nkey] = '/' . $item;
  3339. $hash_replace[$key] = $hash . $item;
  3340. $hash_replace[$nkey] = '/' . $hash . $item;
  3341. $prefix_replace[$key] = $prefix . $item;
  3342. $prefix_replace[$nkey] = '/' . $prefix . $item;
  3343. }
  3344. //prefix standard and replace prefixes
  3345. if ( ! $reverse)
  3346. {
  3347. foreach ($find as $key => $value)
  3348. {
  3349. $tagdata = preg_replace(
  3350. '/(?<![:_])\b(' . preg_quote($value, '/') . ')\b(?![:_])/ms',
  3351. $hash_replace[$key],
  3352. $tagdata
  3353. );
  3354. }
  3355. foreach ($prefix_replace as $key => $value)
  3356. {
  3357. $tagdata = preg_replace(
  3358. '/(?<![:_])\b(' . preg_quote($value, '/') . ')\b(?![:_])/ms',
  3359. $find[$key],
  3360. $tagdata
  3361. );
  3362. }
  3363. //$tagdata = str_replace($find, $hash_replace, $tagdata);
  3364. //$tagdata = str_replace($prefix_replace, $find, $tagdata);
  3365. }
  3366. //we are on the return, fix the hashed ones
  3367. else
  3368. {
  3369. //$tagdata = str_replace($hash_replace, $find, $tagdata);
  3370. foreach ($hash_replace as $key => $value)
  3371. {
  3372. $tagdata = preg_replace(
  3373. '/(?<![:_])\b(' . preg_quote($value, '/') . ')\b(?![:_])/ms',
  3374. $find[$key],
  3375. $tagdata
  3376. );
  3377. }
  3378. }
  3379. return $tagdata;
  3380. }
  3381. //END tag_prefix_replace
  3382. // --------------------------------------------------------------------
  3383. /**
  3384. * Checks first for an error block if present
  3385. *
  3386. * @access protected
  3387. * @param string $line error line
  3388. * @return string parsed html tagdata
  3389. */
  3390. protected function no_results_error($line = '')
  3391. {
  3392. $opener = LD . 'if ';
  3393. $closer = LD . '/if' . RD;
  3394. $q_closer = preg_quote($closer, '/');
  3395. $tagdata = ee()->TMPL->tagdata;
  3396. if ($line != '' AND
  3397. preg_match(
  3398. "/". $opener . preg_quote($this->lower_name) . ":error" .
  3399. RD."(.*?)". $q_closer ."/s",
  3400. $tagdata,
  3401. $match
  3402. )
  3403. )
  3404. {
  3405. //This can have some nested if statements so we need to
  3406. //make sure that we have balanced {if} blocks
  3407. $td = $match[1];
  3408. $openers = substr_count($td, $opener);
  3409. $closers = substr_count($td, $closer);
  3410. //nested IFs?
  3411. if ($openers && $openers > $closers)
  3412. {
  3413. $loop = 0;
  3414. while ($openers != $closers)
  3415. {
  3416. //protection
  3417. if ($loop++ > 500)
  3418. {
  3419. break;
  3420. return ee()->TMPL->no_results();
  3421. }
  3422. $sub_td = substr($tagdata, strpos($tagdata, $td) + strlen($td));
  3423. $td = $td . substr(
  3424. $sub_td,
  3425. strpos($sub_td, $closer),
  3426. strpos($sub_td, $closer) + strlen($closer)
  3427. );
  3428. $openers = substr_count($td, $opener);
  3429. $closers = substr_count($td, $closer);
  3430. }
  3431. }
  3432. $error_tag = $this->lower_name . ":error";
  3433. return ee()->TMPL->parse_variables(
  3434. $td,
  3435. array(array(
  3436. $error_tag => $line,
  3437. 'error_message' => lang($line)
  3438. ))
  3439. );
  3440. }
  3441. else if ( preg_match(
  3442. "/". $opener .preg_quote($this->lower_name).":no_results" .
  3443. RD."(.*?)". $q_closer ."/s",
  3444. $tagdata,
  3445. $match
  3446. )
  3447. )
  3448. {
  3449. return $match[1];
  3450. }
  3451. else
  3452. {
  3453. return ee()->TMPL->no_results();
  3454. }
  3455. }
  3456. //END no_results_error
  3457. // --------------------------------------------------------------------
  3458. /**
  3459. * Replaces CURRENT_USER in tag params
  3460. *
  3461. * @access protected
  3462. * @return null
  3463. */
  3464. protected function replace_current_user()
  3465. {
  3466. if (isset(ee()->TMPL) AND is_object(ee()->TMPL))
  3467. {
  3468. foreach (ee()->TMPL->tagparams as $key => $value)
  3469. {
  3470. if (stristr($value, 'CURRENT_USER'))
  3471. {
  3472. ee()->TMPL->tagparams[$key] = preg_replace(
  3473. '/(?<![:_])\b(CURRENT_USER)\b(?![:_])/ms',
  3474. ee()->session->userdata('member_id'),
  3475. $value
  3476. );
  3477. }
  3478. }
  3479. }
  3480. }
  3481. //END replace_current_user
  3482. // --------------------------------------------------------------------
  3483. /**
  3484. * Replace all form fields tags in the {freeform:all_form_fields} loop
  3485. *
  3486. * @access protected
  3487. * @param string $tagdata incoming tagdata
  3488. * @param array $fields field_id => field_data array
  3489. * @param array $field_order order of field by field id (optional)
  3490. * @param array $field_input_data field input data (optional)
  3491. * @return string transformed output data
  3492. */
  3493. protected function replace_all_form_fields($tagdata,
  3494. $fields,
  3495. $field_order = array(),
  3496. $field_input_data = array())
  3497. {
  3498. // -------------------------------------
  3499. // all form fields loop
  3500. // -------------------------------------
  3501. // this can be used to build normal output
  3502. // or custom output for edit.
  3503. // -------------------------------------
  3504. if (preg_match_all(
  3505. '/' . LD . 'freeform:all_form_fields.*?' . RD .
  3506. '(.*?)' .
  3507. LD . '\/freeform:all_form_fields' . RD . '/ms',
  3508. $tagdata,
  3509. $matches,
  3510. PREG_SET_ORDER
  3511. ))
  3512. {
  3513. $all_field_replace_data = array();
  3514. $field_loop_ids = array_keys($fields);
  3515. // -------------------------------------
  3516. // order ids?
  3517. // -------------------------------------
  3518. if ( ! is_array($field_order) AND is_string($field_order))
  3519. {
  3520. $field_order = $this->actions()->pipe_split($field_order);
  3521. }
  3522. $order_ids = array();
  3523. if (is_array($field_order))
  3524. {
  3525. $order_ids = array_filter($field_order, array($this, 'is_positive_intlike'));
  3526. }
  3527. if ( ! empty($order_ids))
  3528. {
  3529. //this makes sure that any fields in 'fields' are in the
  3530. //order set as well. Will add missing at the end like this
  3531. $field_loop_ids = array_merge(
  3532. $order_ids,
  3533. array_diff($field_loop_ids, $order_ids)
  3534. );
  3535. }
  3536. //build variables
  3537. ee()->load->model('freeform_form_model');
  3538. foreach ($field_loop_ids as $field_id)
  3539. {
  3540. if ( ! isset($fields[$field_id]))
  3541. {
  3542. continue;
  3543. }
  3544. $field_data = $fields[$field_id];
  3545. // -------------------------------------
  3546. // get previous data
  3547. // -------------------------------------
  3548. $col_name = ee()->freeform_form_model->form_field_prefix . $field_id;
  3549. $display_field_data = '';
  3550. if (isset($field_input_data[$field_data['field_name']]))
  3551. {
  3552. $display_field_data = $field_input_data[$field_data['field_name']];
  3553. }
  3554. else if (isset($field_input_data[$col_name]))
  3555. {
  3556. $display_field_data = $field_input_data[$col_name];
  3557. }
  3558. // -------------------------------------
  3559. // load field data
  3560. // -------------------------------------
  3561. $all_field_replace_data[] = array(
  3562. 'freeform:field_id' => $field_id,
  3563. 'freeform:field_data' => $display_field_data,
  3564. 'freeform:field_name' => $field_data['field_name'],
  3565. 'freeform:field_type' => $field_data['field_type'],
  3566. 'freeform:field_label' => LD . 'freeform:label:' .
  3567. $field_data['field_name'] . RD,
  3568. 'freeform:field_output' => LD . 'freeform:field:' .
  3569. $field_data['field_name'] . RD,
  3570. 'freeform:field_description' => LD . 'freeform:description:' .
  3571. $field_data['field_name'] . RD
  3572. );
  3573. }
  3574. foreach ($matches as $match)
  3575. {
  3576. $tagdata_replace = ee()->TMPL->parse_variables(
  3577. $match[1],
  3578. $all_field_replace_data
  3579. );
  3580. $tagdata = str_replace($match[0], $tagdata_replace, $tagdata);
  3581. }
  3582. }
  3583. return $tagdata;
  3584. }
  3585. //END replace_all_form_fields
  3586. // --------------------------------------------------------------------
  3587. /**
  3588. * Parse Status Tags
  3589. *
  3590. * Parses:
  3591. * {freeform:statuses status="not closed|open"}
  3592. * {status_name} {status_value}
  3593. * {/freeform:statuses}
  3594. *
  3595. * @access protected
  3596. * @param string $tagdata tagdata to be parsed
  3597. * @return string adjusted tagdata with status pairs parsed
  3598. */
  3599. protected function parse_status_tags ($tagdata)
  3600. {
  3601. $matches = array();
  3602. $tag = 'freeform:statuses';
  3603. $statuses = $this->data->get_form_statuses();
  3604. preg_match_all(
  3605. '/' . LD . $tag . '.*?' . RD .
  3606. '(.*?)' .
  3607. LD . '\/' . $tag . RD . '/ms',
  3608. $tagdata,
  3609. $matches,
  3610. PREG_SET_ORDER
  3611. );
  3612. if ($matches AND
  3613. isset($matches[0]) AND
  3614. ! empty($matches[0]))
  3615. {
  3616. foreach ($matches as $key => $value)
  3617. {
  3618. $replace_with = '';
  3619. $tdata = $value[1];
  3620. //no need for an if. if we are here, this matched before
  3621. preg_match(
  3622. '/' . LD . $tag . '.*?' . RD . '/',
  3623. $value[0],
  3624. $sub_matches
  3625. );
  3626. // Checking for variables/tags embedded within tags
  3627. // {exp:channel:entries channel="{master_channel_name}"}
  3628. if (stristr(substr($sub_matches[0], 1), LD) !== FALSE)
  3629. {
  3630. $sub_matches[0] = ee()->functions->full_tag(
  3631. $sub_matches[0],
  3632. $value[0]
  3633. );
  3634. // -------------------------------------
  3635. // fix local tagdata
  3636. // -------------------------------------
  3637. preg_match(
  3638. '/' . preg_quote($sub_matches[0]) .
  3639. '(.*?)' .
  3640. LD . '\/' . $tag . RD . '/ms',
  3641. $value[0],
  3642. $tdata_matches
  3643. );
  3644. if (isset($tdata_matches[1]))
  3645. {
  3646. $tdata = $tdata_matches[1];
  3647. }
  3648. }
  3649. $tag_params = ee()->functions->assign_parameters(
  3650. $sub_matches[0]
  3651. );
  3652. $out_status = $statuses;
  3653. if (isset($tag_params['status']))
  3654. {
  3655. $names = strtolower($tag_params['status']);
  3656. $not = FALSE;
  3657. if (preg_match("/^not\s+/s", $names))
  3658. {
  3659. $names = preg_replace('/^not\s+/s', '', $names);
  3660. $not = TRUE;
  3661. }
  3662. $names = preg_split(
  3663. '/\|/s',
  3664. trim($names),
  3665. -1,
  3666. PREG_SPLIT_NO_EMPTY
  3667. );
  3668. foreach ($out_status as $status_name => $status_value)
  3669. {
  3670. if (in_array(strtolower($status_name), $names) == $not)
  3671. {
  3672. unset($out_status[$status_name]);
  3673. }
  3674. }
  3675. }
  3676. foreach ($out_status as $out_name => $out_value)
  3677. {
  3678. $replace_with .= str_replace(
  3679. array(LD . 'status_name' . RD, LD . 'status_label' . RD),
  3680. array($out_name, $out_value),
  3681. $tdata
  3682. );
  3683. }
  3684. //remove
  3685. $tagdata = str_replace($value[0], $replace_with, $tagdata);
  3686. }
  3687. }
  3688. return $tagdata;
  3689. }
  3690. //END parse_status_tags
  3691. // --------------------------------------------------------------------
  3692. /**
  3693. * Runs each fields 'prep_multi_item_data' so that things like 'cat|~|dog'
  3694. * dont show publicly
  3695. *
  3696. * @access public
  3697. * @param string $data incoming data to parse
  3698. * @param string $field_type fieldtype data is from
  3699. * @return string result of prepping multiitem data
  3700. */
  3701. public function prep_multi_item_data($data = '', $field_type = 'text')
  3702. {
  3703. //nothing to do if its empty, yo
  3704. if ( ! $data)
  3705. {
  3706. return $data;
  3707. }
  3708. ee()->load->library('freeform_fields');
  3709. $instance =& ee()->freeform_fields->get_fieldtype_instance(
  3710. $field_type
  3711. );
  3712. $result = $instance->prep_multi_item_data($data);
  3713. //eh, bad dog
  3714. if ( ! $result)
  3715. {
  3716. return $data;
  3717. }
  3718. //array?
  3719. if ( ! is_string($result))
  3720. {
  3721. return implode("\n", (array) $result);
  3722. }
  3723. return $result;
  3724. }
  3725. //END prep_multi_item_data
  3726. // --------------------------------------------------------------------
  3727. /**
  3728. * Replace Submit buttons with args
  3729. *
  3730. * @access public
  3731. * @param array $options input options
  3732. * @return string parsed tagdata
  3733. */
  3734. public function replace_submit($options = array())
  3735. {
  3736. $defaults = array(
  3737. 'pre_args' => array(),
  3738. 'post_args' => array(),
  3739. 'tagdata' => '',
  3740. 'tag' => '',
  3741. 'remove' => false
  3742. );
  3743. //set vars
  3744. foreach($defaults as $key => $value)
  3745. {
  3746. $$key = (isset($options[$key])) ? $options[$key] : $value;
  3747. }
  3748. if (preg_match_all(
  3749. "/" . LD . preg_quote($tag, '/') . "\b(.*?)" . RD . "/ims",
  3750. $tagdata,
  3751. $matches
  3752. )
  3753. )
  3754. {
  3755. $total_matches = count($matches[0]);
  3756. for ($i = 0; $i < $total_matches; $i++)
  3757. {
  3758. // Checking for variables/tags embedded within tags
  3759. // {exp:channel:entries channel="{master_channel_name}"}
  3760. if (stristr(substr($matches[0][$i], 1), LD) !== FALSE)
  3761. {
  3762. $matches[0][$i] = ee()->functions->full_tag($matches[0][$i], $tagdata);
  3763. }
  3764. //if we aren't dealing with just random space
  3765. if (trim($matches[1][$i]) != '')
  3766. {
  3767. $args = ee()->functions->assign_parameters($matches[1][$i]);
  3768. $attr = array();
  3769. if ($args)
  3770. {
  3771. foreach ($args as $key => $value)
  3772. {
  3773. if (substr($key, 0, 5) == 'attr:')
  3774. {
  3775. $attr[substr($key, 5)] = $value;
  3776. }
  3777. }
  3778. }
  3779. //wont work without the name being correct
  3780. $args = array_merge(
  3781. $pre_args,
  3782. $attr,
  3783. $post_args
  3784. );
  3785. if ($remove)
  3786. {
  3787. $tagdata = str_replace(
  3788. $matches[0][$i],
  3789. '',
  3790. $tagdata
  3791. );
  3792. }
  3793. else
  3794. {
  3795. $tagdata = str_replace(
  3796. $matches[0][$i],
  3797. form_submit($args),
  3798. $tagdata
  3799. );
  3800. }
  3801. }
  3802. //END if trim
  3803. }
  3804. //END for
  3805. }
  3806. //END preg_match_all
  3807. return $tagdata;
  3808. }
  3809. //END replace_submit
  3810. // --------------------------------------------------------------------
  3811. /**
  3812. * Do Exit
  3813. *
  3814. * Helper for unit tests so PHP exit isn't fired in the middle of it
  3815. *
  3816. * @access protected
  3817. * @return void
  3818. */
  3819. protected function do_exit()
  3820. {
  3821. if ($this->test_mode)
  3822. {
  3823. return;
  3824. }
  3825. else
  3826. {
  3827. exit();
  3828. }
  3829. }
  3830. //END do_exit
  3831. // --------------------------------------------------------------------
  3832. /**
  3833. * EE 2.7+ restore xid with version check
  3834. * @access public
  3835. * @return voic
  3836. */
  3837. public function restore_xid()
  3838. {
  3839. if (version_compare($this->ee_version, '2.7', '>=') &&
  3840. version_compare($this->ee_version, '2.8', '<'))
  3841. {
  3842. ee()->security->restore_xid();
  3843. }
  3844. }
  3845. //END restore_xid
  3846. }
  3847. // END CLASS Freeform