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

/system/cp/cp.member_import.php

https://github.com/danboy/Croissierd
PHP | 1436 lines | 893 code | 292 blank | 251 comment | 86 complexity | d3119fe73a6291736c3ae7aacd6a3d8b MD5 | raw file
  1. <?php
  2. /*
  3. =====================================================
  4. ExpressionEngine - by EllisLab
  5. -----------------------------------------------------
  6. http://expressionengine.com/
  7. -----------------------------------------------------
  8. Copyright (c) 2003 - 2010 EllisLab, Inc.
  9. =====================================================
  10. THIS IS COPYRIGHTED SOFTWARE
  11. PLEASE READ THE LICENSE AGREEMENT
  12. http://expressionengine.com/docs/license.html
  13. =====================================================
  14. File: cp.member_import.php
  15. -----------------------------------------------------
  16. Purpose: Member Import Utility
  17. =====================================================
  18. */
  19. if ( ! defined('EXT'))
  20. {
  21. exit('Invalid file request');
  22. }
  23. class Member_Import {
  24. var $errors = array();
  25. var $members = array();
  26. var $default_fields = array();
  27. var $delimiter;
  28. var $enclosure;
  29. var $crumbbase = '';
  30. /** -------------------------------------
  31. /** Constructor
  32. /** -------------------------------------*/
  33. function Member_Import()
  34. {
  35. global $IN, $DSP, $LANG, $SESS;
  36. // You have to be a Super Admin to access this page
  37. if ($SESS->userdata['group_id'] != 1)
  38. {
  39. return $DSP->no_access_message();
  40. }
  41. // set breadcrumb base
  42. $this->crumbbase = BASE.AMP.'C=admin'.AMP.'M=utilities'.AMP.'P=member_import';
  43. // Fetch the language file
  44. $LANG->fetch_language_file('member_import');
  45. switch($IN->GBL('F'))
  46. {
  47. case 'convert_data' : $this->convert_data();
  48. break;
  49. case 'xml_import' : $this->xml_import();
  50. break;
  51. case 'confirm_xml_form' : $this->confirm_xml_form();
  52. break;
  53. case 'process_xml' : $this->process_xml();
  54. break;
  55. case 'pair_fields' : $this->pair_fields();
  56. break;
  57. case 'confirm_data_form' : $this->confirm_data_form();
  58. break;
  59. case 'create_xml' : $this->create_xml();
  60. break;
  61. default : $this->member_import_main_page();
  62. break;
  63. }
  64. }
  65. /* END */
  66. /** -------------------------------------
  67. /** Member Import Main Page
  68. /** -------------------------------------*/
  69. function member_import_main_page()
  70. {
  71. global $DSP, $LANG;
  72. $DSP->title = $LANG->line('member_import_utility');
  73. $DSP->crumb = $LANG->line('member_import_utility');
  74. $r = $DSP->qdiv('tableHeading', $LANG->line('member_import_utility'));
  75. $r .= $DSP->qdiv('tableHeadingAlt', $DSP->heading($LANG->line('member_import_welcome'), 5));
  76. $r .= $DSP->div('box');
  77. $r .= $DSP->qdiv('defaultBold', $DSP->anchor($this->crumbbase.AMP.'F=xml_import', $LANG->line('import_from_xml')));
  78. $r .= $DSP->qdiv('itemWrapper', $LANG->line('import_from_xml_blurb'));
  79. $r .= $DSP->div_c();
  80. $r .= $DSP->div('box');
  81. $r .= $DSP->qdiv('defaultBold', $DSP->anchor($this->crumbbase.AMP.'F=convert_data', $LANG->line('convert_from_delimited')));
  82. $r .= $DSP->qdiv('itemWrapper', $LANG->line('convert_from_delimited_blurb'));
  83. $r .= $DSP->div_c();
  84. $DSP->body = $r;
  85. }
  86. /* END */
  87. /** -------------------------------------
  88. /** XML Import
  89. /** -------------------------------------*/
  90. function xml_import()
  91. {
  92. global $DB, $DSP, $LANG, $LOC, $SESS, $PREFS;
  93. $DSP->title = $LANG->line('import_from_xml');
  94. $DSP->crumb = $DSP->anchor($this->crumbbase, $LANG->line('member_import_utility')).$DSP->crumb_item($LANG->line('import_from_xml'));
  95. $r = $DSP->qdiv('tableHeading', $LANG->line('import_from_xml'));
  96. $r .= $DSP->qdiv('tableHeadingAlt', $DSP->heading($LANG->line('import_from_xml_blurb'), 5));
  97. $r .= $DSP->div('box');
  98. $r .= $DSP->heading($LANG->line('import_info'));
  99. $r .= $DSP->qdiv('itemWrapper', $DSP->qdiv('highlight_alt', $LANG->line('info_blurb')));
  100. $r .= $DSP->qdiv('simpleLine', NBS);
  101. $r .= $DSP->form_open(array('action' => 'C=admin'.AMP.'M=utilities'.AMP.'P=member_import'.AMP.'F=confirm_xml_form','name' => 'file_form'));
  102. $r .= $DSP->div('itemWrapper').
  103. $DSP->qdiv('itemTitle', $LANG->line('xml_file_loc')).
  104. $DSP->qdiv('itemWrapper', $LANG->line('xml_file_loc_blurb')).
  105. $DSP->input_text('xml_file', '', '40', '70', 'input', '300px').
  106. $DSP->div_c();
  107. $r .= $DSP->qdiv('simpleLine', NBS);
  108. $r .= $DSP->heading($LANG->line('default_settings'));
  109. $r .= $DSP->qdiv('itemWrapper', $LANG->line('default_settings_blurb'));
  110. /** -------------------------------------
  111. /** Fetch Member Groups
  112. /** -------------------------------------*/
  113. $query = $DB->query("SELECT DISTINCT group_id, group_title FROM exp_member_groups WHERE site_id = '".$DB->escape_str($PREFS->ini('site_id'))."' order by group_title");
  114. $menu = $DSP->input_select_header('group_id');
  115. foreach ($query->result as $row)
  116. {
  117. $menu .= $DSP->input_select_option($row['group_id'], $row['group_title']);
  118. }
  119. $menu .= $DSP->input_select_footer();
  120. $r .= $DSP->div('itemWrapper').
  121. $DSP->qdiv('itemTitle', $LANG->line('default_group_id')).
  122. $menu.
  123. $DSP->div_c();
  124. /** -------------------------------------
  125. /** Languages
  126. /** -------------------------------------*/
  127. $source_dir = PATH_LANG;
  128. $dirs = array();
  129. if ($fp = @opendir($source_dir))
  130. {
  131. while (FALSE !== ($file = readdir($fp)))
  132. {
  133. if (is_dir($source_dir.$file) && substr($file, 0, 1) != ".")
  134. {
  135. $dirs[] = $file;
  136. }
  137. }
  138. closedir($fp);
  139. }
  140. sort($dirs);
  141. $r .= $DSP->div('itemWrapper').
  142. $DSP->qdiv('itemTitle', $LANG->line('language')).
  143. $DSP->input_select_header('language').
  144. $DSP->input_select_option($LANG->line('none'), $LANG->line('none'));
  145. foreach ($dirs as $dir)
  146. {
  147. $r .= $DSP->input_select_option($dir, ucfirst($dir));
  148. }
  149. $r .= $DSP->input_select_footer();
  150. $r .= $DSP->div_c();
  151. /** -------------------------------------
  152. /** Timezone
  153. /** -------------------------------------*/
  154. $r .= $DSP->div('itemWrapper').
  155. $DSP->qdiv('itemTitle', $LANG->line('timezone')).
  156. $LOC->timezone_menu('UTC').
  157. $DSP->div_c();
  158. /** -------------------------------------
  159. /** Time Format
  160. /** -------------------------------------*/
  161. $r .= $DSP->div('itemWrapper').
  162. $DSP->qdiv('itemTitle', $LANG->line('time_format')).
  163. $DSP->input_select_header('time_format').
  164. $DSP->input_select_option('us', $LANG->line('united_states')).
  165. $DSP->input_select_option('eu', $LANG->line('european')).
  166. $DSP->input_select_footer().
  167. $DSP->div_c();
  168. /** -------------------------------------
  169. /** DST setting
  170. /** -------------------------------------*/
  171. $dst = ($SESS->userdata('daylight_savings') == 'y') ? 1 : 0;
  172. $r .= $DSP->div('itemWrapper').
  173. $DSP->qdiv('itemTitle', $LANG->line('daylight_savings')).
  174. $DSP->qdiv('itemWrapper', $DSP->input_checkbox('daylight_savings', 'y', $dst).
  175. '<label for="daylight_savings">'.$LANG->line('dst_enabled').'</label>').
  176. $DSP->div_c();
  177. $r .= $DSP->qdiv('simpleLine', NBS);
  178. $r .= $DSP->qdiv('itemWrapper', $DSP->input_submit('Submit'));
  179. $r .= $DSP->form_close();
  180. $r .= $DSP->div_c();
  181. $DSP->body = $r;
  182. }
  183. /* END */
  184. /** -------------------------------------
  185. /** XML Form Confirmation
  186. /** -------------------------------------*/
  187. function confirm_xml_form()
  188. {
  189. global $DB, $DSP, $IN, $LANG, $LOC;
  190. /** -------------------------------------
  191. /** Snag POST data, prepared for db insertion
  192. /** -------------------------------------*/
  193. $data = array(
  194. 'xml_file' => ( ! $IN->GBL('xml_file', 'POST')) ? '' : $IN->GBL('xml_file', 'POST'),
  195. 'group_id' => $IN->GBL('group_id', 'POST'),
  196. 'language' => ($IN->GBL('language', 'POST') == $LANG->line('none')) ? '' : $IN->GBL('language', 'POST'),
  197. 'timezone' => $IN->GBL('server_timezone', 'POST'),
  198. 'time_format' => $IN->GBL('time_format', 'POST'),
  199. 'daylight_savings' => ($IN->GBL('daylight_savings', 'POST') == 'y') ? 'y' : 'n'
  200. );
  201. if ($data['xml_file'] == '')
  202. {
  203. return $DSP->error_message($LANG->line('no_file_submitted'));
  204. }
  205. /** -------------------------------------
  206. /** Begin Output
  207. /** -------------------------------------*/
  208. $DSP->title = $LANG->line('confirm_details');
  209. $DSP->crumb = $DSP->anchor($this->crumbbase, $LANG->line('member_import_utility')).
  210. $DSP->crumb_item($DSP->anchor($this->crumbbase.AMP.'F=xml_import', $LANG->line('import_from_xml'))).
  211. $DSP->crumb_item($LANG->line('confirm_details'));
  212. $r = $DSP->qdiv('tableHeading', $LANG->line('confirm_details'));
  213. $r .= $DSP->qdiv('box', $DSP->qdiv('itemWrapper', $LANG->line('confirm_details_blurb')));
  214. $r .= $DSP->div('box');
  215. $r .= $DSP->table_open(array('class' => 'tableBorder', 'style' => 'width: 600px'));
  216. $r .= $DSP->table_row(array(
  217. array('class' => 'tableHeadingAlt', 'text' => $LANG->line('option')),
  218. array('class' => 'tableHeadingAlt', 'text' => $LANG->line('value'))
  219. )
  220. );
  221. $i = 0;
  222. foreach ($data as $key => $val)
  223. {
  224. $class = ($i % 2) ? 'tableCellOne' : 'tableCellTwo'; $i++;
  225. /** -------------------------------------
  226. /** Our values need pretty-fication
  227. /** -------------------------------------*/
  228. switch ($key)
  229. {
  230. case 'group_id':
  231. $query = $DB->query("SELECT DISTINCT group_title FROM exp_member_groups where group_id = '".$data[$key]."'");
  232. $val = $query->row['group_title'];
  233. break;
  234. case 'language':
  235. $val = ($val == '') ? 'None' : ucfirst($val);
  236. break;
  237. case 'timezone':
  238. $val = $LANG->line($val);
  239. break;
  240. case 'daylight_savings':
  241. $val = ($val == 'y') ? $LANG->line('yes') : $LANG->line('no');
  242. break;
  243. case 'time_format':
  244. $val = ($val == 'us') ? $LANG->line('united_states') : $LANG->line('european');
  245. break;
  246. }
  247. $r .= $DSP->table_row(array(
  248. array('class' => $class, 'style' => 'width: 200px', 'text' => $LANG->line($key)),
  249. array('class' => $class, 'text' => $DSP->span('highlight_alt').$val.$DSP->span_c())
  250. )
  251. );
  252. }
  253. $r .= $DSP->table_close();
  254. $r .= $DSP->div_c();
  255. $r .= $DSP->qdiv('box alert', $LANG->line('member_id_warning'));
  256. $r .= $DSP->div('box');
  257. $r .= $DSP->form_open(
  258. array(
  259. 'action' => 'C=admin'.AMP.'M=utilities'.AMP.'P=member_import'.AMP.'F=process_xml',
  260. 'method' => 'post',
  261. 'name' => 'confirmForm',
  262. 'id' => 'confirmForm',
  263. ),
  264. $data
  265. );
  266. $r .= $DSP->qdiv('itemWrapper', $DSP->input_submit($LANG->line('import')));
  267. $r .= $DSP->form_close();
  268. $r .= $DSP->div_c();
  269. $DSP->body = $r;
  270. }
  271. /** -------------------------------------
  272. /** Check and Process XML File
  273. /** -------------------------------------*/
  274. function process_xml()
  275. {
  276. global $DSP, $IN, $LANG;
  277. $xml_file = ( ! $IN->GBL('xml_file', 'POST')) ? '' : $IN->GBL('xml_file', 'POST');
  278. /** -------------------------------------
  279. /** Check file path
  280. /** -------------------------------------*/
  281. if (($exists = $this->check_file($xml_file)) !== TRUE)
  282. {
  283. return;
  284. }
  285. /** -------------------------------------
  286. /** Read XML file contents
  287. /** -------------------------------------*/
  288. if (function_exists('file_get_contents'))
  289. {
  290. $contents = file_get_contents($xml_file);
  291. }
  292. else
  293. {
  294. $fp = fopen($xml_file, 'r');
  295. $contents = fread($fp, filesize($xml_file));
  296. fclose($fp);
  297. }
  298. /** -------------------------------------
  299. /** Instantiate EE_XMLparser Class
  300. /** -------------------------------------*/
  301. if ( ! class_exists('EE_XMLparser'))
  302. {
  303. require PATH_CORE.'core.xmlparser'.EXT;
  304. }
  305. $XML = new EE_XMLparser;
  306. // parse XML data
  307. $xml = $XML->parse_xml($contents);
  308. $this->validate_xml($xml);
  309. /** -------------------------------------
  310. /** Show Errors
  311. /** -------------------------------------*/
  312. if (count($this->errors) > 0)
  313. {
  314. $msg = '';
  315. foreach($this->errors as $error)
  316. {
  317. foreach($error as $val)
  318. {
  319. $msg .= $val.'<br />';
  320. }
  321. }
  322. return $DSP->error_message($msg);
  323. }
  324. /** -------------------------------------
  325. /** Ok! Cross Fingers and do it!
  326. /** -------------------------------------*/
  327. $imports = $this->do_import();
  328. /** -------------------------------------
  329. /** Begin Output
  330. /** -------------------------------------*/
  331. $DSP->title = $LANG->line('xml_imported');
  332. $DSP->crumb = $DSP->anchor($this->crumbbase, $LANG->line('member_import_utility')).
  333. $DSP->crumb_item($LANG->line('xml_imported'));
  334. $r = $DSP->qdiv('tableHeading', $LANG->line('import_success'));
  335. $r .= $DSP->div('box');
  336. $r .= $DSP->qdiv('itemWrapper', $LANG->line('import_success_blurb'));
  337. $r .= $DSP->qdiv('itemWrapper', str_replace('%x', $imports, $LANG->line('total_members_imported')));
  338. $r .= $DSP->div_c();
  339. $DSP->body = $r;
  340. }
  341. /* END */
  342. /** -------------------------------------
  343. /** Validate XML Member file
  344. /** -------------------------------------*/
  345. function validate_xml($xml)
  346. {
  347. global $DB, $DSP, $FNS, $LANG, $PREFS;
  348. if ( ! class_exists('Validate'))
  349. {
  350. require PATH_CORE.'core.validate'.EXT;
  351. }
  352. $VAL = new Validate(
  353. array(
  354. 'member_id' => '',
  355. 'val_type' => 'new',
  356. 'fetch_lang' => TRUE,
  357. 'require_cpw' => FALSE,
  358. 'enable_log' => FALSE,
  359. 'cur_username' => '',
  360. 'cur_screen_name' => '',
  361. 'cur_password' => '',
  362. 'cur_email' => '',
  363. )
  364. );
  365. $i = 0;
  366. /** -------------------------------------
  367. /** Retreive Valid fields from database
  368. /** -------------------------------------*/
  369. $query = $DB->query("SHOW COLUMNS FROM exp_members");
  370. foreach ($query->result as $row)
  371. {
  372. $this->default_fields[$row['Field']] = '';
  373. }
  374. // we don't allow <unique_id>
  375. unset($this->default_fields['unique_id']);
  376. $u = array(); // username garbage array
  377. $s = array(); // screen_name garbage array
  378. $e = array(); // email garbage array
  379. $m = array(); // member_id garbage array
  380. if (is_array($xml->children[0]->children))
  381. {
  382. foreach($xml->children as $member)
  383. {
  384. if ($member->tag == "member")
  385. {
  386. foreach($member->children as $tag)
  387. {
  388. // Is the XML tag an allowed database field
  389. if ( ! isset($this->default_fields[$tag->tag]) || $tag->tag == 'unique_id')
  390. {
  391. // We have a special XML format for birthdays that doesn't match the database fields
  392. if ($tag->tag == 'birthday')
  393. {
  394. foreach($tag->children as $birthday)
  395. {
  396. switch ($birthday->tag)
  397. {
  398. case 'day':
  399. $this->members[$i]['bday_d'] = $birthday->value;
  400. break;
  401. case 'month':
  402. $this->members[$i]['bday_m'] = $birthday->value;
  403. break;
  404. case 'year':
  405. $this->members[$i]['bday_y'] = $birthday->value;
  406. break;
  407. default:
  408. $this->errors[] = array($LANG->line('invalid_tag')." '&lt;".$birthday->tag."&gt;'");
  409. break;
  410. }
  411. }
  412. if ( ! isset($this->members[$i]['bday_d']) || ! isset($this->members[$i]['bday_m']) || ! isset($this->members[$i]['bday_y']))
  413. {
  414. $this->errors[] = array($LANG->line('missing_birthday_child'));
  415. }
  416. }
  417. else
  418. {
  419. // not a database field and not a <birthday> so club it like a baby seal!
  420. $this->errors[] = array($LANG->line('invalid_tag')." '&lt;".$tag->tag."&gt;'");
  421. }
  422. }
  423. $this->members[$i][$tag->tag] = $tag->value;
  424. /* -------------------------------------
  425. /* username, screen_name, and email
  426. /* must be validated and unique
  427. /* -------------------------------------*/
  428. switch ($tag->tag)
  429. {
  430. case 'username':
  431. $VAL->username = $tag->value;
  432. if ( ! in_array($tag->value, $u))
  433. {
  434. $u[] = $tag->value;
  435. }
  436. else
  437. {
  438. $this->errors[] = array($LANG->line('duplicate_username').$tag->value);
  439. }
  440. break;
  441. case 'screen_name':
  442. $VAL->screen_name = $tag->value;
  443. if ( ! in_array($tag->value, $s))
  444. {
  445. $s[] = $tag->value;
  446. }
  447. else
  448. {
  449. $this->errors[] = array($LANG->line('duplicate_screen_name').$tag->value);
  450. }
  451. break;
  452. case 'email':
  453. if ( ! in_array($tag->value, $e) OR $PREFS->ini('allow_multi_emails') == 'y')
  454. {
  455. $e[] = $tag->value;
  456. }
  457. else
  458. {
  459. $this->errors[] = array($LANG->line('duplicate_email').$tag->value);
  460. }
  461. $VAL->email = $tag->value;
  462. break;
  463. case 'member_id':
  464. if ( ! in_array($tag->value, $m))
  465. {
  466. $m[] = $tag->value;
  467. }
  468. else
  469. {
  470. $this->errors[] = array(str_replace("%x", $tag->value, $LANG->line('duplicate_member_id')));
  471. }
  472. break;
  473. case 'password':
  474. // encode password if it is type="text"
  475. $this->members[$i][$tag->tag] = ($tag->attributes['type'] == 'text') ? $FNS->hash($tag->value) : $tag->value;
  476. break;
  477. }
  478. }
  479. $username = (isset($this->members[$i]['username'])) ? $this->members[$i]['username'] : '';
  480. $screen_name = (isset($this->members[$i]['screen_name'])) ? $this->members[$i]['screen_name'] : '';
  481. $email = (isset($this->members[$i]['email'])) ? $this->members[$i]['email'] : '';
  482. /* -------------------------------------
  483. /* Validate separately to display
  484. /* exact problem
  485. /* -------------------------------------*/
  486. $VAL->validate_username();
  487. if ( ! empty($VAL->errors))
  488. {
  489. foreach($VAL->errors as $key => $val)
  490. {
  491. $VAL->errors[$key] = $val." (Username: '".$username."' - ".$LANG->line('within_user_record')." '".$username."')";
  492. }
  493. $this->errors[] = $VAL->errors;
  494. unset($VAL->errors);
  495. }
  496. $VAL->validate_screen_name();
  497. if ( ! empty($VAL->errors))
  498. {
  499. foreach($VAL->errors as $key => $val)
  500. {
  501. $VAL->errors[$key] = $val." (Screen Name: '".$screen_name."' - ".$LANG->line('within_user_record')." '".$username."')";
  502. }
  503. $this->errors[] = $VAL->errors;
  504. unset($VAL->errors);
  505. }
  506. $VAL->validate_email();
  507. if ( ! empty($VAL->errors))
  508. {
  509. foreach($VAL->errors as $key => $val)
  510. {
  511. $VAL->errors[$key] = $val." (Email: '".$email."' - ".$LANG->line('within_user_record')." '".$username."')";
  512. }
  513. $this->errors[] = $VAL->errors;
  514. unset($VAL->errors);
  515. }
  516. /** -------------------------------------
  517. /** Add a random hash if no password is defined
  518. /** -------------------------------------*/
  519. if ( ! isset($this->members[$i]['password']))
  520. {
  521. $this->members[$i]['password'] = $FNS->hash(mt_rand());
  522. }
  523. $i++;
  524. }
  525. else
  526. {
  527. /** -------------------------------------
  528. /** Element isn't <member>
  529. /** -------------------------------------*/
  530. $this->errors[] = array($LANG->line('invalid_element'));
  531. }
  532. }
  533. }
  534. else
  535. {
  536. /** -------------------------------------
  537. /** No children of the root element
  538. /** -------------------------------------*/
  539. $this->errors[] = array($LANG->line('invalid_xml'));
  540. }
  541. }
  542. /* END */
  543. /** -------------------------------------
  544. /** Perform XML Member Import
  545. /** -------------------------------------*/
  546. function do_import()
  547. {
  548. global $DB, $DSP, $FNS, $IN, $LANG, $LOC, $STAT;
  549. /** -------------------------------------
  550. /** Set our optional default values
  551. /** -------------------------------------*/
  552. $this->default_fields['group_id'] = $IN->GBL('group_id', 'POST');
  553. $this->default_fields['language'] = ($IN->GBL('language', 'POST') == $LANG->line('none')) ? '' : $IN->GBL('language', 'POST');
  554. $this->default_fields['timezone'] = $IN->GBL('timezone', 'POST');
  555. $this->default_fields['time_format'] = $IN->GBL('time_format', 'POST');
  556. $this->default_fields['daylight_savings'] = ($IN->GBL('daylight_savings', 'POST') == 'y') ? 'y' : 'n';
  557. $this->default_fields['ip_address'] = '0.0.0.0';
  558. $this->default_fields['join_date'] = $LOC->now;
  559. /** -------------------------------------
  560. /** Rev it up, no turning back!
  561. /** -------------------------------------*/
  562. $new_ids = array();
  563. $counter = 0;
  564. foreach ($this->members as $member)
  565. {
  566. $data = array();
  567. $dupe = FALSE;
  568. foreach ($this->default_fields as $key => $val)
  569. {
  570. if (isset($member[$key]))
  571. {
  572. $data[$key] = $member[$key];
  573. }
  574. elseif ($val != '')
  575. {
  576. $data[$key] = $val;
  577. }
  578. }
  579. /** -------------------------------------
  580. /** Add a unique_id for each member
  581. /** -------------------------------------*/
  582. $data['unique_id'] = $FNS->random('encrypt');
  583. /* -------------------------------------
  584. /* See if we've already imported a member with this member_id -
  585. /* could possibly occur if an auto_increment value is used
  586. /* before a specified member_id.
  587. /* -------------------------------------*/
  588. if (isset($data['member_id']))
  589. {
  590. if (isset($new_ids[$data['member_id']]))
  591. {
  592. /* -------------------------------------
  593. /* Grab the member so we can re-insert it after we
  594. /* take care of this nonsense
  595. /* -------------------------------------*/
  596. $dupe = TRUE;
  597. $tempdata = $DB->query("SELECT * FROM exp_members WHERE member_id = '".$data['member_id']."'");
  598. }
  599. }
  600. /* -------------------------------------
  601. /* Shove it in!
  602. /* We are using REPLACE as we want to overwrite existing members if a member id is specified
  603. /* -------------------------------------*/
  604. $sql = str_replace('INSERT', 'REPLACE', $DB->insert_string('exp_members', $data));
  605. $DB->query($sql);
  606. /** -------------------------------------
  607. /** Add the member id to the array of imported member id's
  608. /** -------------------------------------*/
  609. $new_ids[$DB->insert_id] = '';
  610. /** -------------------------------------
  611. /** Insert the old auto_incremented member, if necessary
  612. /** -------------------------------------*/
  613. if ($dupe === TRUE)
  614. {
  615. unset($tempdata->row['member_id']); // dump the member_id so it can auto_increment a new one
  616. $DB->query($DB->insert_string('exp_members', $tempdata->row));
  617. $new_ids[$DB->insert_id] = '';
  618. }
  619. $counter++;
  620. }
  621. /** -------------------------------------
  622. /** Add records to exp_member_data and exp_member_homepage tables for all imported members
  623. /** -------------------------------------*/
  624. $values = '';
  625. foreach ($new_ids as $key => $val)
  626. {
  627. $values .= "('$key'),";
  628. }
  629. $values = substr($values, 0, -1);
  630. $DB->query("INSERT INTO exp_member_data (member_id) VALUES ".$values);
  631. $DB->query("INSERT INTO exp_member_homepage (member_id) VALUES ".$values);
  632. /** -------------------------------------
  633. /** Update Statistics
  634. /** -------------------------------------*/
  635. $STAT->update_member_stats();
  636. return $counter;
  637. }
  638. /* END */
  639. /** -------------------------------------
  640. /** Convert Delimited Data
  641. /** -------------------------------------*/
  642. function convert_data()
  643. {
  644. global $DSP, $LANG;
  645. /** -------------------------------------
  646. /** Begin Output
  647. /** -------------------------------------*/
  648. $DSP->title = $LANG->line('convert_from_delimited');
  649. $DSP->crumb = $DSP->anchor($this->crumbbase, $LANG->line('member_import_utility')).
  650. $DSP->crumb_item($LANG->line('convert_from_delimited'));
  651. $r = $DSP->qdiv('tableHeading', $LANG->line('convert_from_delimited'));
  652. $r .= $DSP->qdiv('tableHeadingAlt', $DSP->heading($LANG->line('convert_from_delimited_blurb'), 5));
  653. $r .= $DSP->div('box');
  654. $r .= $DSP->heading($LANG->line('import_info'));
  655. $r .= $DSP->qdiv('itemWrapper', $DSP->qdiv('highlight_alt', $LANG->line('info_blurb')));
  656. $r .= $DSP->qdiv('simpleLine', NBS);
  657. $r .= $DSP->form_open(array(
  658. 'action' => 'C=admin'.AMP.
  659. 'M=utilities'.AMP.
  660. 'P=member_import'.AMP.
  661. 'F=pair_fields',
  662. 'name' => 'file_form'
  663. )
  664. );
  665. $r .= $DSP->div('itemWrapper').
  666. $DSP->qdiv('itemTitle', $LANG->line('delimited_file_loc')).
  667. $DSP->qdiv('itemWrapper', $LANG->line('file_loc_blurb')).
  668. $DSP->input_text('member_file', '', '40', '70', 'input', '300px').
  669. $DSP->div_c();
  670. $r .= $DSP->qdiv('simpleLine', NBS);
  671. $r .= $DSP->div('itemWrapper');
  672. $r .= $DSP->qdiv('itemTitle', $LANG->line('delimiter'));
  673. $r .= $DSP->qdiv('itemWrapper', $LANG->line('delimiter_blurb'));
  674. $delimit_opts = array('tab' => "tab", 'comma' => ',' , 'other' => 'other');
  675. foreach ($delimit_opts as $key => $val)
  676. {
  677. $checked = ($key == 'tab') ? 1 : 0;
  678. $r .= $DSP->input_radio('delimiter', $val, $checked);
  679. $r .= '<label for="delimiter">'.$LANG->line($key).'</label>';
  680. $r .= $DSP->nbs(2);
  681. }
  682. $r .= $DSP->input_text('delimiter_special', '', 5, 2, 'input', 5, 'onclick="this.form.delimiter[2].click();return false"');
  683. $r .= $DSP->div_c();
  684. $r .= $DSP->div('itemWrapper');
  685. $r .= $DSP->qdiv('itemTitle', $LANG->line('enclosure'));
  686. $r .= $DSP->qdiv('itemWrapper', $LANG->line('enclosure_blurb'));
  687. $r .= $DSP->qdiv('highlight_alt', '<code>'.$LANG->line('enclosure_example').'</code>');
  688. $r .= $DSP->qdiv('itemWrapper',
  689. '<label for="enclosure">'.$LANG->line('enclosure_label').'</label>'.
  690. $DSP->input_text('enclosure', '', 5, 2, 'input', 5)
  691. );
  692. $r .= $DSP->div_c();
  693. $r .= $DSP->qdiv('simpleLine', NBS);
  694. $r .= $DSP->qdiv('itemWrapper', $DSP->input_submit($LANG->line('submit')));
  695. $r .= $DSP->form_close();
  696. $r .= $DSP->div_c();
  697. $DSP->body = $r;
  698. }
  699. /* END */
  700. /** -------------------------------------
  701. /** Pair delimited data with Member fields
  702. /** -------------------------------------*/
  703. function pair_fields()
  704. {
  705. global $DB, $DSP, $IN, $LANG;
  706. /** -------------------------------------
  707. /** Snag form POST data
  708. /** -------------------------------------*/
  709. $member_file = ( ! $IN->GBL('member_file', 'POST')) ? '' : $IN->GBL('member_file', 'POST');
  710. switch ($IN->GBL('delimiter', 'POST'))
  711. {
  712. case 'tab' : $this->delimiter = "\t"; break;
  713. case ',' : $this->delimiter = ","; break;
  714. case 'other':
  715. $this->delimiter = trim($IN->GBL('delimiter_special', 'POST'));
  716. preg_match("/[\w\d]*/", $this->delimiter, $matches);
  717. if ($matches[0] != '')
  718. return $DSP->error_message($LANG->line('alphanumeric_not_allowed'));
  719. break;
  720. }
  721. $this->enclosure = ( ! $IN->GBL('enclosure', 'POST')) ? '' : $this->prep_enclosure($IN->GBL('enclosure', 'POST'));
  722. /** -------------------------------------
  723. /** Make sure file exists
  724. /** -------------------------------------*/
  725. $exists = $this->check_file($member_file);
  726. if ($exists !== TRUE)
  727. return;
  728. if ($this->delimiter == '')
  729. {
  730. return $DSP->error_message(str_replace('%x', $LANG->line('other'), $LANG->line('no_delimiter')));
  731. }
  732. /** -------------------------------------
  733. /** Read data file into an array
  734. /** -------------------------------------*/
  735. $fields = $this->datafile_to_array($member_file);
  736. if (count($fields[0]) < 3)
  737. {
  738. // No point going further if there aren't even the minimum required
  739. return $DSP->error_message($LANG->line('not_enough_fields'));
  740. }
  741. /** -------------------------------------
  742. /** Begin Output
  743. /** -------------------------------------*/
  744. $DSP->title = $LANG->line('member_import_utility');
  745. $DSP->crumb = $DSP->anchor($this->crumbbase, $LANG->line('member_import_utility')).
  746. $DSP->crumb_item($DSP->anchor($this->crumbbase.AMP.'F=convert_data', $LANG->line('convert_from_delimited'))).
  747. $DSP->crumb_item($LANG->line('assign_fields'));
  748. $r = $DSP->qdiv('tableHeading', $LANG->line('member_import_utility'));
  749. $r .= $DSP->div('box');
  750. $r .= $DSP->heading($LANG->line('assign_fields'));
  751. $r .= $DSP->qdiv('itemWrapper', $LANG->line('assign_fields_blurb'));
  752. $r .= $DSP->qdiv('itemWrapper', $DSP->qdiv('alert', $LANG->line('password_field_warning')));
  753. $r .= $DSP->div_c();
  754. /** -------------------------------------
  755. /** Retreive Valid fields from database
  756. /** -------------------------------------*/
  757. $query = $DB->query("SHOW COLUMNS FROM exp_members");
  758. foreach ($query->result as $row)
  759. {
  760. $this->default_fields[$row['Field']] = '';
  761. }
  762. // we do not allow <unique_id> in our XML format
  763. unset($this->default_fields['unique_id']);
  764. ksort($this->default_fields);
  765. $select_options = '';
  766. foreach ($this->default_fields as $key => $val)
  767. {
  768. $select_options .= $DSP->input_select_option($key, $key);
  769. }
  770. /** -------------------------------------
  771. /** Display table and form
  772. /** -------------------------------------*/
  773. $r .= $DSP->div('box');
  774. $r .= $DSP->qdiv('itemWrapper', $DSP->qdiv('highlight_alt', $LANG->line('required_fields')));
  775. $r .= $DSP->form_open(
  776. array(
  777. 'action' => 'C=admin'.AMP.'M=utilities'.AMP.'P=member_import'.AMP.'F=confirm_data_form',
  778. 'method' => 'post',
  779. 'name' => 'entryform',
  780. 'id' => 'entryform'
  781. ),
  782. array(
  783. 'member_file' => $IN->GBL('member_file', 'POST'),
  784. 'delimiter' => $IN->GBL('delimiter', 'POST'),
  785. 'enclosure' => $this->enclosure,
  786. 'delimiter_special' => $this->delimiter
  787. )
  788. );
  789. $r .= $DSP->table_open(array('class' => 'tableBorder', 'style' => 'width: 600px'));
  790. $r .= $DSP->table_row(array(
  791. array('class' => 'tableHeading', 'text' => $LANG->line('your_data')),
  792. array('class' => 'tableHeading', 'text' => $LANG->line('member_fields'))
  793. )
  794. );
  795. $i = 0;
  796. foreach ($fields[0] as $field)
  797. {
  798. $class = ($i % 2) ? 'tableCellOne' : 'tableCellTwo'; $i++;
  799. $r .= $DSP->table_row(array(
  800. array('class' => $class, 'text' => $field),
  801. array(
  802. 'class' => $class,
  803. 'text' => $DSP->input_select_header('field_'.$i).
  804. $select_options.
  805. $DSP->input_select_footer()
  806. )
  807. )
  808. );
  809. }
  810. $r .= $DSP->table_close();
  811. $r .= $DSP->qdiv('itemWrapper', $DSP->input_checkbox('encrypt', 'y').'<label for="encrypt">'.$LANG->line('plaintext_passwords').'</label>');
  812. $r .= $DSP->qdiv('simpleLine', NBS);
  813. $r .= $DSP->qdiv('itemWrapper', $DSP->input_submit());
  814. $r .= $DSP->form_close();
  815. $r .= $DSP->div_c();
  816. $r .= $DSP->qdiv('simpleLine', NBS);
  817. $r .= $DSP->div_c();
  818. $DSP->body = $r;
  819. }
  820. /* END */
  821. /** -------------------------------------
  822. /** Confirm Data to XML Form
  823. /** -------------------------------------*/
  824. function confirm_data_form()
  825. {
  826. global $DSP, $IN, $LANG;
  827. /** -------------------------------------
  828. /** Snag POST data
  829. /** -------------------------------------*/
  830. $member_file = ( ! $IN->GBL('member_file', 'POST')) ? '' : $IN->GBL('member_file', 'POST');
  831. switch ($IN->GBL('delimiter', 'POST'))
  832. {
  833. case 'tab' : $this->delimiter = "\t"; break;
  834. case ',' : $this->delimiter = ","; break;
  835. case 'other': $this->delimiter = $IN->GBL('delimiter_special', 'POST');
  836. }
  837. $this->enclosure = ( ! $IN->GBL('enclosure', 'POST')) ? '' : $this->prep_enclosure($IN->GBL('enclosure', 'POST'));
  838. $encrypt = ($IN->GBL('encrypt', 'POST') == 'y') ? TRUE : FALSE;
  839. /** -------------------------------------
  840. /** Get field pairings
  841. /** -------------------------------------*/
  842. $paired = array();
  843. foreach ($_POST as $key => $val)
  844. {
  845. if (substr($key, 0, 5) == 'field')
  846. {
  847. if (in_array($val, $paired))
  848. {
  849. return $DSP->error_message(str_replace("%x", $val, $LANG->line('duplicate_field_assignment')));
  850. }
  851. $paired[$key] = $val;
  852. }
  853. }
  854. if (! in_array('username', $paired))
  855. {
  856. return $DSP->error_message($LANG->line('missing_username_field'));
  857. }
  858. if (! in_array('screen_name', $paired))
  859. {
  860. return $DSP->error_message($LANG->line('missing_screen_name_field'));
  861. }
  862. if (! in_array('email', $paired))
  863. {
  864. return $DSP->error_message($LANG->line('missing_email_field'));
  865. }
  866. /** -------------------------------------
  867. /** Read the data file
  868. /** -------------------------------------*/
  869. $fields = $this->datafile_to_array($member_file);
  870. /** -------------------------------------
  871. /** Begin Output
  872. /** -------------------------------------*/
  873. $DSP->title = $LANG->line('member_import_utility');
  874. $DSP->crumb = $DSP->anchor($this->crumbbase, $LANG->line('member_import_utility')).
  875. $DSP->crumb_item($DSP->anchor($this->crumbbase.AMP.'F=convert_data', $LANG->line('convert_from_delimited'))).
  876. $DSP->crumb_item($LANG->line('confirm_field_assignment'));
  877. $r = $DSP->qdiv('tableHeading', $LANG->line('member_import_utility'));
  878. $r .= $DSP->div('box');
  879. $r .= $DSP->heading($LANG->line('confirm_field_assignment'));
  880. $r .= $DSP->qdiv('itemWrapper', $LANG->line('confirm_field_assignment_blurb'));
  881. $r .= $DSP->div_c();
  882. /** -------------------------------------
  883. /** Begin form and table
  884. /** -------------------------------------*/
  885. $r .= $DSP->div('box');
  886. $r .= $DSP->form_open(
  887. array(
  888. 'action' => 'C=admin'.AMP.'M=utilities'.AMP.'P=member_import'.AMP.'F=create_xml',
  889. 'method' => 'post',
  890. 'name' => 'entryform',
  891. 'id' => 'entryform'
  892. ),
  893. array(
  894. 'member_file' => $IN->GBL('member_file', 'POST'),
  895. 'delimiter' => $IN->GBL('delimiter', 'POST'),
  896. 'delimiter_special' => $this->delimiter,
  897. 'enclosure' => $this->enclosure,
  898. 'encrypt' => $IN->GBL('encrypt', 'POST')
  899. )
  900. );
  901. foreach ($paired as $key => $val)
  902. {
  903. $r .= $DSP->input_hidden($key, $val);
  904. }
  905. $r .= $DSP->table_open(array('class' => 'tableBorder', 'style' => 'width: 600px'));
  906. $r .= $DSP->table_row(array(
  907. array('class' => 'tableHeading', 'text' => $LANG->line('your_data')),
  908. array('class' => 'tableHeading', 'text' => $LANG->line('member_fields'))
  909. )
  910. );
  911. $i = 0;
  912. foreach ($fields[0] as $key => $val)
  913. {
  914. $class = ($i % 2) ? 'tableCellOne' : 'tableCellTwo'; $i++;
  915. $r .= $DSP->table_row(array(
  916. array('class' => $class, 'text' => $val),
  917. array(
  918. 'class' => $class,
  919. 'text' => $DSP->span('highlight_alt').$paired['field_'.($key + 1)].$DSP->span_c()
  920. )
  921. )
  922. );
  923. }
  924. $r .= $DSP->table_close();
  925. $r .= $DSP->qdiv('itemWrapper', $DSP->qdiv('alert', ($encrypt === TRUE) ? $LANG->line('plaintext_passwords') : $LANG->line('encrypted_passwords')));
  926. $r .= $DSP->qdiv('simpleLine', NBS);
  927. $r .= $DSP->qdiv('radio', $DSP->input_radio('type', 'view').$LANG->line('view_in_browser'));
  928. $r .= $DSP->qdiv('radio', $DSP->input_radio('type', 'download', 1).$LANG->line('download'));
  929. $r .= $DSP->qdiv('itemWrapper', $DSP->input_submit());
  930. $r .= $DSP->form_close();
  931. $r .= $DSP->div_c();
  932. $DSP->body = $r;
  933. }
  934. /* END */
  935. /** -------------------------------------
  936. /** Create XML File
  937. /** -------------------------------------*/
  938. function create_xml()
  939. {
  940. global $DSP, $IN, $LANG, $OUT;
  941. /** -------------------------------------
  942. /** Snag POST data
  943. /** -------------------------------------*/
  944. $member_file = ( ! $IN->GBL('member_file', 'POST')) ? '' : $IN->GBL('member_file', 'POST');
  945. switch ($IN->GBL('delimiter', 'POST'))
  946. {
  947. case 'tab' : $this->delimiter = "\t"; break;
  948. case ',' : $this->delimiter = ","; break;
  949. case 'other': $this->delimiter = $IN->GBL('delimiter_special', 'POST');
  950. }
  951. $this->enclosure = ( ! $IN->GBL('enclosure', 'POST')) ? '' : $this->prep_enclosure($IN->GBL('enclosure', 'POST'));
  952. $encrypt = ($IN->GBL('encrypt', 'POST') == 'y') ? TRUE : FALSE;
  953. $type = $IN->GBL('type', 'POST');
  954. /** -------------------------------------
  955. /** Read file contents
  956. /** -------------------------------------*/
  957. if (function_exists('file_get_contents'))
  958. {
  959. $contents = file_get_contents($member_file);
  960. }
  961. else
  962. {
  963. $fp = fopen($member_file, 'r');
  964. $contents = fread($fp, filesize($member_file));
  965. fclose($fp);
  966. }
  967. /** -------------------------------------
  968. /** Get structure
  969. /** -------------------------------------*/
  970. $structure = array();
  971. foreach ($_POST as $key => $val)
  972. {
  973. if (substr($key, 0, 5) == 'field')
  974. {
  975. $structure[] = $val;
  976. }
  977. }
  978. /** -------------------------------------
  979. /** Instantiate EE_XMLparser Class
  980. /** -------------------------------------*/
  981. if ( ! class_exists('EE_XMLparser'))
  982. {
  983. require PATH_CORE.'core.xmlparser'.EXT;
  984. }
  985. $XML = new EE_XMLparser;
  986. /** -------------------------------------
  987. /** Convert the data to XML
  988. /** -------------------------------------*/
  989. $params = array(
  990. 'data' => $contents,
  991. 'structure' => $structure,
  992. 'root' => 'members',
  993. 'element' => 'member',
  994. 'delimiter' => $this->delimiter,
  995. 'enclosure' => $this->enclosure
  996. );
  997. $xml = $XML->delimited_to_xml($params);
  998. /** -------------------------------------
  999. /** Add type="text" parameter for plaintext passwords
  1000. /** -------------------------------------*/
  1001. if ($encrypt === TRUE)
  1002. {
  1003. $xml = str_replace('<password>', '<password type="text">', $xml);
  1004. }
  1005. if ( ! empty($XML->errors))
  1006. {
  1007. $OUT->show_user_error('general', $XML->errors);
  1008. exit;
  1009. }
  1010. /** -------------------------------------
  1011. /** Output to browser or download
  1012. /** -------------------------------------*/
  1013. switch ($type)
  1014. {
  1015. case 'view' : $this->view_xml($xml); break;
  1016. case 'download' : $this->download_xml($xml); break;
  1017. }
  1018. }
  1019. /* END */
  1020. /** -------------------------------------
  1021. /** View XML in browser
  1022. /** -------------------------------------*/
  1023. function view_xml($xml)
  1024. {
  1025. global $DSP, $LANG;
  1026. $DSP->title = $LANG->line('member_import_utility');
  1027. $DSP->crumb = $DSP->anchor($this->crumbbase, $LANG->line('member_import_utility')).
  1028. $DSP->crumb_item($LANG->line('view_xml'));
  1029. $DSP->body = $DSP->qdiv('tableHeading', $LANG->line('member_import_utility'));
  1030. $DSP->body .= $DSP->div('box');
  1031. $DSP->body .= $DSP->heading($LANG->line('view_xml'));
  1032. $xml = str_replace("\n", BR, htmlentities($xml));
  1033. $xml = str_replace("\t", $DSP->NBS(4), $xml);
  1034. $DSP->body .= $xml;
  1035. $DSP->body .= $DSP->div_c();
  1036. }
  1037. /* END */
  1038. /** -------------------------------------
  1039. /** I wondered why the baseball was getting bigger. Then it hit me.
  1040. /** -------------------------------------*/
  1041. /** -------------------------------------
  1042. /** Download XML file
  1043. /** -------------------------------------*/
  1044. function download_xml($xml)
  1045. {
  1046. global $DSP, $LANG, $LOC;
  1047. $now = $LOC->set_localized_time();
  1048. $filename = 'member_'.date('y', $now).date('m', $now).date('d', $now).'.xml';
  1049. ob_start();
  1050. if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE") || strstr($_SERVER['HTTP_USER_AGENT'], "OPERA"))
  1051. {
  1052. $mime = 'application/octetstream';
  1053. }
  1054. else
  1055. {
  1056. $mime = 'application/octet-stream';
  1057. }
  1058. if (strstr($_SERVER['HTTP_USER_AGENT'], "MSIE"))
  1059. {
  1060. header('Content-Type: '.$mime);
  1061. header('Content-Disposition: inline; filename="'.$filename.'"');
  1062. header('Expires: 0');
  1063. header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
  1064. header('Pragma: public');
  1065. }
  1066. else
  1067. {
  1068. header('Content-Type: '.$mime);
  1069. header('Content-Disposition: attachment; filename="'.$filename.'"');
  1070. header('Expires: 0');
  1071. header('Pragma: no-cache');
  1072. }
  1073. echo $xml;
  1074. $buffer = ob_get_contents();
  1075. ob_end_clean();
  1076. echo $buffer;
  1077. exit;
  1078. }
  1079. /* END */
  1080. /** -------------------------------------
  1081. /** Validate file path
  1082. /** -------------------------------------*/
  1083. function check_file($file)
  1084. {
  1085. global $DSP, $LANG;
  1086. if ($file == '')
  1087. {
  1088. return $DSP->error_message($LANG->line('no_file_submitted'));
  1089. }
  1090. if ( ! file_exists($file))
  1091. {
  1092. return $DSP->error_message($LANG->line('invalid_path').$file);
  1093. }
  1094. return TRUE;
  1095. }
  1096. /* END */
  1097. /** -------------------------------------
  1098. /** Read delimited data file into array
  1099. /** -------------------------------------*/
  1100. function datafile_to_array($file)
  1101. {
  1102. $contents = file($file);
  1103. $fields = array();
  1104. /** -------------------------------------
  1105. /** Parse file into array
  1106. /** -------------------------------------*/
  1107. if ($this->enclosure == '')
  1108. {
  1109. foreach ($contents as $line)
  1110. {
  1111. $fields[] = explode($this->delimiter, $line);
  1112. }
  1113. }
  1114. else
  1115. {
  1116. foreach ($contents as $line)
  1117. {
  1118. preg_match_all("/".preg_quote($this->enclosure)."(.*?)".preg_quote($this->enclosure)."/si", $line, $matches);
  1119. $fields[] = $matches[1];
  1120. }
  1121. }
  1122. return $fields;
  1123. }
  1124. /* END */
  1125. /** -------------------------------------
  1126. /** Prep Enclosure
  1127. /** -------------------------------------*/
  1128. function prep_enclosure($enclosure)
  1129. {
  1130. // undo changes made by form prep as we need the literal characters
  1131. // and htmlspecialchars_decode() doesn't exist until PHP 5, so...
  1132. $enclosure = str_replace('&#39;', "'", $enclosure);
  1133. $enclosure = str_replace('&amp;', "&", $enclosure);
  1134. $enclosure = str_replace('&lt;', "<", $enclosure);
  1135. $enclosure = str_replace('&gt;', ">", $enclosure);
  1136. $enclosure = str_replace('&quot;', '"', $enclosure);
  1137. $enclosure = stripslashes($enclosure);
  1138. return $enclosure;
  1139. }
  1140. }
  1141. /* END */
  1142. ?>