profile.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. <?php
  2. // $Id: profile.php 11280 2007-02-28 14:12:14Z elixir_inter $
  3. /*
  4. ==============================================================================
  5. Dokeos - elearning and course management software
  6. Copyright (c) 2004 Dokeos S.A.
  7. Copyright (c) 2003 Ghent University (UGent)
  8. Copyright (c) 2001 Universite catholique de Louvain (UCL)
  9. Copyright (c) Roan Embrechts (Vrije Universiteit Brussel)
  10. For a full list of contributors, see "credits.txt".
  11. The full license can be read in "license.txt".
  12. This program is free software; you can redistribute it and/or
  13. modify it under the terms of the GNU General Public License
  14. as published by the Free Software Foundation; either version 2
  15. of the License, or (at your option) any later version.
  16. See the GNU General Public License for more details.
  17. Contact address: Dokeos, 44 rue des palais, B-1030 Brussels, Belgium
  18. Mail: info@dokeos.com
  19. ==============================================================================
  20. */
  21. /**
  22. ==============================================================================
  23. * This file displays the user's profile,
  24. * optionally it allows users to modify their profile as well.
  25. *
  26. * See inc/conf/profile.conf.php to modify settings
  27. *
  28. * @package dokeos.auth
  29. ==============================================================================
  30. */
  31. /*
  32. ==============================================================================
  33. INIT SECTION
  34. ==============================================================================
  35. */
  36. // name of the language file that needs to be included
  37. $language_file = 'registration';
  38. $cidReset = true;
  39. require ('../inc/global.inc.php');
  40. require_once (api_get_path(LIBRARY_PATH).'formvalidator/FormValidator.class.php');
  41. $this_section = SECTION_MYPROFILE;
  42. api_block_anonymous_users();
  43. $htmlHeadXtra[] = '<script type="text/javascript">
  44. function confirmation(name)
  45. {
  46. if (confirm("'.get_lang('AreYouSureToDelete').' " + name + " ?"))
  47. {return true;}
  48. else
  49. {return false;}
  50. }
  51. </script>';
  52. if (!empty ($_GET['coursePath']))
  53. {
  54. $course_url = api_get_path(WEB_COURSE_PATH).htmlentities(strip_tags($_GET['coursePath'])).'/index.php';
  55. $interbreadcrumb[] = array ('url' => $course_url, 'name' => $_GET['courseCode']);
  56. }
  57. /*
  58. -----------------------------------------------------------
  59. Configuration file
  60. -----------------------------------------------------------
  61. */
  62. require_once (api_get_path(CONFIGURATION_PATH).'profile.conf.php');
  63. /*
  64. -----------------------------------------------------------
  65. Libraries
  66. -----------------------------------------------------------
  67. */
  68. include_once (api_get_path(LIBRARY_PATH).'fileManage.lib.php');
  69. include_once (api_get_path(LIBRARY_PATH).'fileUpload.lib.php');
  70. if (is_profile_editable())
  71. $tool_name = get_lang('ModifProfile');
  72. else
  73. $tool_name = get_lang('ViewProfile');
  74. $table_user = Database :: get_main_table(TABLE_MAIN_USER);
  75. /*
  76. -----------------------------------------------------------
  77. Form
  78. -----------------------------------------------------------
  79. */
  80. /*
  81. * Get initial values for all fields.
  82. */
  83. $sql = "SELECT * FROM $table_user WHERE user_id = '".$_user['user_id']."'";
  84. $result = api_sql_query($sql, __FILE__, __LINE__);
  85. if ($result)
  86. {
  87. $user_data = mysql_fetch_array($result, MYSQL_ASSOC);
  88. if (is_null($user_data['language']))
  89. $user_data['language'] = api_get_setting('platformLanguage');
  90. }
  91. $fck_attribute['Height'] = "150";
  92. $fck_attribute['Width'] = "450";
  93. $fck_attribute['ToolbarSet'] = "Profil";
  94. /*
  95. * Initialize the form.
  96. */
  97. $form = new FormValidator('profile', 'post', "{$_SERVER['PHP_SELF']}?{$_SERVER['QUERY_STRING']}", null, array('style' => 'width: 60%; float: '.($text_dir=='rtl'?'right;':'left;')));
  98. /* Make sure this is the first submit on the form, even though it is hidden!
  99. * Otherwise, if a user has productions and presses ENTER to submit, he will
  100. * attempt to delete the first production in the list. */
  101. if (is_profile_editable())
  102. $form->addElement('submit', null, get_lang('Ok'), array('style' => 'visibility:hidden;'));
  103. // LAST NAME and FIRST NAME
  104. $form->addElement('text', 'lastname', get_lang('LastName'), array('size' => 40));
  105. $form->addElement('text', 'firstname', get_lang('FirstName'), array('size' => 40));
  106. if (api_get_setting('profile', 'name') !== 'true')
  107. $form->freeze(array('lastname', 'firstname'));
  108. $form->applyFilter(array('lastname', 'firstname'), 'stripslashes');
  109. $form->applyFilter(array('lastname', 'firstname'), 'trim');
  110. $form->addRule('lastname' , get_lang('ThisFieldIsRequired'), 'required');
  111. $form->addRule('firstname', get_lang('ThisFieldIsRequired'), 'required');
  112. // OFFICIAL CODE
  113. if (CONFVAL_ASK_FOR_OFFICIAL_CODE)
  114. {
  115. $form->addElement('text', 'official_code', get_lang('OfficialCode'), array('size' => 40));
  116. if (api_get_setting('profile', 'officialcode') !== 'true')
  117. $form->freeze('official_code');
  118. $form->applyFilter('official_code', 'stripslashes');
  119. $form->applyFilter('official_code', 'trim');
  120. if (api_get_setting('registration', 'officialcode') == 'true' && api_get_setting('profile', 'officialcode') == 'true')
  121. $form->addRule('official_code', get_lang('ThisFieldIsRequired'), 'required');
  122. }
  123. // EMAIL
  124. $form->addElement('text', 'email', get_lang('Email'), array('size' => 40));
  125. if (api_get_setting('profile', 'email') !== 'true')
  126. $form->freeze('email');
  127. $form->applyFilter('email', 'stripslashes');
  128. $form->applyFilter('email', 'trim');
  129. if (api_get_setting('registration', 'email') == 'true')
  130. $form->addRule('email', get_lang('ThisFieldIsRequired'), 'required');
  131. $form->addRule('email', get_lang('EmailWrong'), 'email');
  132. // PHONE
  133. $form->addElement('text', 'phone', get_lang('phone'), array('size' => 20));
  134. if (api_get_setting('profile', 'phone') !== 'true')
  135. $form->freeze('phone');
  136. $form->applyFilter('phone', 'stripslashes');
  137. $form->applyFilter('phone', 'trim');
  138. /*if (api_get_setting('registration', 'phone') == 'true')
  139. $form->addRule('phone', get_lang('ThisFieldIsRequired'), 'required');
  140. $form->addRule('phone', get_lang('EmailWrong'), 'email');*/
  141. // PICTURE
  142. if (is_profile_editable() && api_get_setting('profile', 'picture') == 'true')
  143. {
  144. $form->addElement('file', 'picture', (get_user_image($_user['user_id']) != '' ? get_lang('UpdateImage') : get_lang('AddImage')));
  145. $form->add_progress_bar();
  146. if( strlen($user_data['picture_uri']) > 0)
  147. {
  148. $form->addElement('checkbox', 'remove_picture', null, get_lang('DelImage'));
  149. }
  150. $form->addRule('picture', get_lang('OnlyImagesAllowed'), 'mimetype', array('image/gif', 'image/jpeg', 'image/png'));
  151. }
  152. // USERNAME
  153. $form->addElement('text', 'username', get_lang('UserName'), array('size' => 40));
  154. if (api_get_setting('profile', 'login') !== 'true')
  155. $form->freeze('username');
  156. $form->applyFilter('username', 'stripslashes');
  157. $form->applyFilter('username', 'trim');
  158. $form->addRule('username', get_lang('ThisFieldIsRequired'), 'required');
  159. $form->addRule('username', get_lang('UsernameWrong'), 'username');
  160. $form->addRule('username', get_lang('UserTaken'), 'username_available', $user_data['username']);
  161. // LANGUAGE
  162. $form->addElement('select_language', 'language', get_lang('Language'));
  163. if (api_get_setting('profile', 'language') !== 'true')
  164. $form->freeze('language');
  165. // EXTENDED PROFILE
  166. if (api_get_setting('extended_profile') == 'true')
  167. {
  168. $form->addElement('static', null, '<em>'.get_lang('OptionalTextFields').'</em>');
  169. // MY COMPETENCES
  170. $form->add_html_editor('competences', get_lang('MyCompetences'), false);
  171. // MY DIPLOMAS
  172. $form->add_html_editor('diplomas', get_lang('MyDiplomas'), false);
  173. // WHAT I AM ABLE TO TEACH
  174. $form->add_html_editor('teach', get_lang('MyTeach'), false);
  175. // MY PRODUCTIONS
  176. $form->addElement('file', 'production', get_lang('MyProductions'));
  177. if ($production_list = build_production_list($_user['user_id']))
  178. $form->addElement('static', 'productions', null, $production_list);
  179. // MY PERSONAL OPEN AREA
  180. $form->add_html_editor('openarea', get_lang('MyPersonalOpenArea'), false);
  181. $form->applyFilter(array('competences', 'diplomas', 'teach', 'openarea'), 'stripslashes');
  182. $form->applyFilter(array('competences', 'diplomas', 'teach'), 'trim'); // openarea is untrimmed for maximum openness
  183. }
  184. // PASSWORD
  185. if (is_profile_editable() && api_get_setting('profile', 'password') == 'true')
  186. {
  187. $form->addElement('static', null, null, '<em>'.get_lang('Enter2passToChange').'</em>');
  188. $form->addElement('password', 'password1', get_lang('Pass'), array('size' => 40));
  189. $form->addElement('password', 'password2', get_lang('Confirmation'), array('size' => 40));
  190. // user must enter identical password twice so we can prevent some user errors
  191. $form->addRule(array('password1', 'password2'), get_lang('PassTwo'), 'compare');
  192. if (CHECK_PASS_EASY_TO_FIND)
  193. $form->addRule('password1', get_lang('PassTooEasy').': '.api_generate_password(), 'callback', 'api_check_password');
  194. }
  195. // SUBMIT
  196. if (is_profile_editable())
  197. {
  198. $form->addElement('submit', 'apply_change', get_lang('Ok'));
  199. }
  200. else
  201. {
  202. $form->freeze();
  203. }
  204. /*
  205. * Set initial values for all fields.
  206. */
  207. $form->setDefaults($user_data);
  208. /*
  209. ==============================================================================
  210. FUNCTIONS
  211. ==============================================================================
  212. */
  213. /*
  214. -----------------------------------------------------------
  215. LOGIC FUNCTIONS
  216. -----------------------------------------------------------
  217. */
  218. /**
  219. * Can a user edit his/her profile?
  220. *
  221. * @return boolean Editability of the profile
  222. */
  223. function is_profile_editable()
  224. {
  225. return $GLOBALS['profileIsEditable'];
  226. }
  227. /*
  228. -----------------------------------------------------------
  229. USER IMAGE FUNCTIONS
  230. -----------------------------------------------------------
  231. */
  232. /**
  233. * Get a user's display picture. If the user doesn't have a picture, this
  234. * function will return an empty string.
  235. *
  236. * @param $user_id User id
  237. * @return The uri to the picture
  238. */
  239. function get_user_image($user_id)
  240. {
  241. $table_user = Database :: get_main_table(TABLE_MAIN_USER);
  242. $sql = "SELECT picture_uri FROM $table_user WHERE user_id = '$user_id'";
  243. $result = api_sql_query($sql, __FILE__, __LINE__);
  244. if ($result && $row = mysql_fetch_array($result, MYSQL_ASSOC))
  245. $image = trim($row['picture_uri']);
  246. else
  247. $image = '';
  248. return $image;
  249. }
  250. /**
  251. * Upload a submitted user image.
  252. *
  253. * @param $user_id User id
  254. * @return The filename of the new picture or FALSE if the upload has failed
  255. */
  256. function upload_user_image($user_id)
  257. {
  258. /* Originally added by Miguel (miguel@cesga.es) - 2003-11-04
  259. * Code Refactoring by Hugues Peeters (hugues.peeters@claroline.net) - 2003-11-24
  260. * Moved inside a function and refactored by Thomas Corthals - 2005-11-04
  261. */
  262. $image_repository = api_get_path(SYS_CODE_PATH).'upload/users/';
  263. $existing_image = get_user_image($user_id);
  264. $file_extension = explode('.', $_FILES['picture']['name']);
  265. $file_extension = strtolower($file_extension[sizeof($file_extension) - 1]);
  266. if (!file_exists($image_repository))
  267. mkpath($image_repository);
  268. if ($existing_image != '')
  269. {
  270. if (KEEP_THE_NAME_WHEN_CHANGE_IMAGE)
  271. {
  272. $picture_filename = $existing_image;
  273. $old_picture_filename = 'saved_'.date('Y_m_d_H_i_s').'_'.uniqid('').'_'.$existing_image;
  274. }
  275. else
  276. {
  277. $old_picture_filename = $existing_image;
  278. $picture_filename = (PREFIX_IMAGE_FILENAME_WITH_UID ? 'u'.$user_id.'_' : '').uniqid('').'.'.$file_extension;
  279. }
  280. if (KEEP_THE_OLD_IMAGE_AFTER_CHANGE)
  281. rename($image_repository.$existing_image, $image_repository.$old_picture_filename);
  282. else
  283. unlink($image_repository.$existing_image);
  284. }
  285. else
  286. {
  287. $picture_filename = (PREFIX_IMAGE_FILENAME_WITH_UID ? $user_id.'_' : '').uniqid('').'.'.$file_extension;
  288. }
  289. if (move_uploaded_file($_FILES['picture']['tmp_name'], $image_repository.$picture_filename))
  290. return $picture_filename;
  291. return false; // this should be returned if anything went wrong with the upload
  292. }
  293. /**
  294. * Remove an existing user image.
  295. *
  296. * @param $user_id User id
  297. */
  298. function remove_user_image($user_id)
  299. {
  300. $image_repository = api_get_path(SYS_CODE_PATH).'upload/users/';
  301. $image = get_user_image($user_id);
  302. if ($image != '')
  303. {
  304. if (KEEP_THE_OLD_IMAGE_AFTER_CHANGE)
  305. rename($image_repository.$image, $image_repository.'deleted_'.date('Y_m_d_H_i_s').'_'.$image);
  306. else
  307. unlink($image_repository.$image);
  308. }
  309. }
  310. /*
  311. -----------------------------------------------------------
  312. PRODUCTIONS FUNCTIONS
  313. -----------------------------------------------------------
  314. */
  315. /**
  316. * Returns an XHTML formatted list of productions for a user, or FALSE if he
  317. * doesn't have any.
  318. *
  319. * If there has been a request to remove a production, the function will return
  320. * without building the list unless forced to do so by the optional second
  321. * parameter. This increases performance by avoiding to read through the
  322. * productions on the filesystem before the removal request has been carried
  323. * out because they'll have to be re-read afterwards anyway.
  324. *
  325. * @param $user_id User id
  326. * @param $force Optional parameter to force building after a removal request
  327. * @return A string containing the XHTML code to dipslay the production list, or FALSE
  328. */
  329. function build_production_list($user_id, $force = false)
  330. {
  331. if (!$force && $_POST['remove_production'])
  332. return true; // postpone reading from the filesystem
  333. $productions = get_user_productions($user_id);
  334. if (empty($productions))
  335. return false;
  336. $production_dir = api_get_path(WEB_CODE_PATH)."upload/users/$user_id/";
  337. $del_image = api_get_path(WEB_CODE_PATH).'img/delete.gif';
  338. $del_text = get_lang('Delete');
  339. $production_list = '<ul id="productions">';
  340. foreach ($productions as $file)
  341. {
  342. $production_list .= '<li><a href="'.$production_dir.urlencode($file).'" target="_blank">'.htmlentities($file).'</a>';
  343. $production_list .= '<input type="image" name="remove_production['.urlencode($file).']" src="'.$del_image.'" alt="'.$del_text.'" title="'.$del_text.' '.htmlentities($file).'" onclick="return confirmation(\''.htmlentities($file).'\');" /></li>';
  344. }
  345. $production_list .= '</ul>';
  346. return $production_list;
  347. }
  348. /**
  349. * Returns an array with the user's productions.
  350. *
  351. * @param $user_id User id
  352. * @return An array containing the user's productions
  353. */
  354. function get_user_productions($user_id)
  355. {
  356. $production_repository = api_get_path(SYS_CODE_PATH)."upload/users/$user_id/";
  357. $productions = array();
  358. if (is_dir($production_repository))
  359. {
  360. $handle = opendir($production_repository);
  361. while ($file = readdir($handle))
  362. {
  363. if ($file == '.' || $file == '..' || $file == '.htaccess')
  364. continue; // skip current/parent directory and .htaccess
  365. $productions[] = $file;
  366. }
  367. }
  368. return $productions; // can be an empty array
  369. }
  370. /**
  371. * Upload a submitted user production.
  372. *
  373. * @param $user_id User id
  374. * @return The filename of the new production or FALSE if the upload has failed
  375. */
  376. function upload_user_production($user_id)
  377. {
  378. $production_repository = api_get_path(SYS_CODE_PATH)."upload/users/$user_id/";
  379. if (!file_exists($production_repository))
  380. mkpath($production_repository);
  381. $filename = replace_dangerous_char($_FILES['production']['name']);
  382. $filename = php2phps($filename);
  383. if (move_uploaded_file($_FILES['production']['tmp_name'], $production_repository.$filename))
  384. return $filename;
  385. return false; // this should be returned if anything went wrong with the upload
  386. }
  387. /**
  388. * Remove a user production.
  389. *
  390. * @param $user_id User id
  391. * @param $production The production to remove
  392. */
  393. function remove_user_production($user_id, $production)
  394. {
  395. unlink(api_get_path(SYS_CODE_PATH)."upload/users/$user_id/$production");
  396. }
  397. /*
  398. ==============================================================================
  399. MAIN CODE
  400. ==============================================================================
  401. */
  402. if ($_SESSION['profile_update'])
  403. {
  404. $update_success = ($_SESSION['profile_update'] == 'success');
  405. unset($_SESSION['profile_update']);
  406. }
  407. elseif ($_POST['remove_production'])
  408. {
  409. foreach (array_keys($_POST['remove_production']) as $production)
  410. remove_user_production($_user['user_id'], urldecode($production));
  411. if ($production_list = build_production_list($_user['user_id'], true))
  412. $form->insertElementBefore($form->createElement('static', null, null, $production_list), 'productions');
  413. $form->removeElement('productions');
  414. $file_deleted = true;
  415. }
  416. elseif ($form->validate())
  417. {
  418. $user_data = $form->exportValues();
  419. // set password if a new one was provided
  420. if ($user_data['password1'])
  421. $password = $user_data['password1'];
  422. // upload picture if a new one is provided
  423. if ($_FILES['picture']['size'])
  424. {
  425. if ($new_picture = upload_user_image($_user['user_id']))
  426. $user_data['picture_uri'] = $new_picture;
  427. }
  428. // remove existing picture if asked
  429. elseif ($user_data['remove_picture'])
  430. {
  431. remove_user_image($_user['user_id']);
  432. $user_data['picture_uri'] = '';
  433. }
  434. // upload production if a new one is provided
  435. if ($_FILES['production']['size'])
  436. upload_user_production($_user['user_id']);
  437. // remove values that shouldn't go in the database
  438. unset($user_data['password1'], $user_data['password2'], $user_data['MAX_FILE_SIZE'],
  439. $user_data['remove_picture'], $user_data['apply_change']);
  440. // build SQL query
  441. $sql = "UPDATE $table_user SET";
  442. foreach($user_data as $key => $value)
  443. {
  444. $sql .= " $key = '".addslashes($value)."',";
  445. }
  446. if (isset($password))
  447. {
  448. if ($userPasswordCrypted)
  449. {
  450. $sql .= " password = MD5('".addslashes($password)."')";
  451. }
  452. else
  453. {
  454. $sql .= " password = '".addslashes($password)."'";
  455. }
  456. }
  457. else // remove trailing , from the query we have so far
  458. {
  459. $sql = rtrim($sql, ',');
  460. }
  461. $sql .= " WHERE user_id = '".$_user['user_id']."'";
  462. api_sql_query($sql, __FILE__, __LINE__);
  463. // re-init the system to take new settings into account
  464. $uidReset = true;
  465. include (api_get_path(INCLUDE_PATH).'local.inc.php');
  466. $_SESSION['profile_update'] = 'success';
  467. header("Location: http://{$_SERVER['HTTP_HOST']}{$_SERVER['PHP_SELF']}?{$_SERVER['QUERY_STRING']}");
  468. exit;
  469. }
  470. /*
  471. ==============================================================================
  472. MAIN DISPLAY SECTION
  473. ==============================================================================
  474. */
  475. Display :: display_header(get_lang('ModifyProfile'));
  476. if ($file_deleted)
  477. {
  478. Display :: display_normal_message(get_lang('FileDeleted'));
  479. }
  480. elseif ($update_success)
  481. {
  482. Display :: display_normal_message(get_lang('ProfileReg'));
  483. }
  484. // USER PICTURE
  485. $image = get_user_image($_user['user_id']);
  486. $image_file = ($image != '' ? api_get_path(WEB_CODE_PATH)."upload/users/$image" : api_get_path(WEB_CODE_PATH).'img/unknown.jpg');
  487. $image_size = @getimagesize($image_file);
  488. $img_attributes = 'src="'.$image_file.'?rand='.time().'" '
  489. .'alt="'.$user_data['lastname'].' '.$user_data['firstname'].'" '
  490. .'style="float:'.($text_dir == 'rtl' ? 'left' : 'right').'; padding:5px;" ';
  491. if ($image_size[0] > 300) //limit display width to 300px
  492. $img_attributes .= 'width="300" ';
  493. echo '<img '.$img_attributes.'/>';
  494. $form->display();
  495. echo '<div id="myprofilefooter">
  496. <a href="'.api_get_path(WEB_CODE_PATH).'tracking/personnalLog.php">'.get_lang('MyStats').'</a>
  497. | <a href="'.api_get_path(WEB_CODE_PATH).'auth/courses.php">'.get_lang('MyCourses').'</a></div>';
  498. Display :: display_footer();
  499. ?>