user.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402
  1. <?php
  2. require_once "../config.php";
  3. require_once "../db/table.php";
  4. require_once "../db/channel.php";
  5. require_once "../public/function.php";
  6. // Require Composer's autoloader.
  7. require_once '../../vendor/autoload.php';
  8. use Firebase\JWT\JWT;
  9. use Firebase\JWT\Key;
  10. // Using Medoo namespace.
  11. use Medoo\Medoo;
  12. // Require Composer's autoloader.
  13. use PHPMailer\PHPMailer\PHPMailer;
  14. use PHPMailer\PHPMailer\SMTP;
  15. use PHPMailer\PHPMailer\Exception;
  16. /*
  17. CREATE TABLE users (
  18. id INTEGER PRIMARY KEY AUTOINCREMENT,
  19. like_type VARCHAR (16) NOT NULL,
  20. resource_type VARCHAR (32) NOT NULL,
  21. resource_id CHAR (36) NOT NULL,
  22. user_id INTEGER NOT NULL,
  23. created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL //只做初始化,更新时不自动更新
  24. updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP NOT NULL //自动更新
  25. );
  26. */
  27. class PCD_User extends Table
  28. {
  29. function __construct($redis=false) {
  30. parent::__construct(_FILE_DB_USERINFO_, _TABLE_USER_INFO_, _DB_USERNAME_,_DB_PASSWORD_,$redis);
  31. }
  32. public function index(){
  33. $where["like_type"] = "like";
  34. $where["resource_type"] = $_GET["type"];
  35. $where["resource_id"] = explode($_GET["id"],",");
  36. echo json_encode($this->_index(["resource_id","user_id"],$where), JSON_UNESCAPED_UNICODE);
  37. }
  38. public function list(){
  39. if(!isset($_COOKIE["userid"])){
  40. $userId = $_COOKIE["userid"];
  41. }
  42. $json = file_get_contents('php://input');
  43. $data = json_decode($json,true);
  44. foreach ($data as $key => $value) {
  45. # code...
  46. $data[$key]['like']=$this->medoo->count($this->table,[
  47. 'like_type'=>$value['like_type'],
  48. 'resource_type'=>$value['resource_type'],
  49. 'resource_id'=>$value['resource_id'],
  50. ]);
  51. }
  52. if(isset($_COOKIE["userid"])){
  53. $userId = $_COOKIE["userid"];
  54. foreach ($data as $key => $value) {
  55. # code...
  56. $data[$key]['me']=$this->medoo->count($this->table,[
  57. 'like_type'=>$value['like_type'],
  58. 'resource_type'=>$value['resource_type'],
  59. 'resource_id'=>$value['resource_id'],
  60. 'user_id'=>$userId,
  61. ]);
  62. }
  63. }
  64. $this->result["ok"]=true;
  65. $this->result["message"]="";
  66. $this->result["data"]=$data;
  67. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  68. }
  69. public function create(){
  70. $json = file_get_contents('php://input');
  71. $data = json_decode($json,true);
  72. //验证邀请码
  73. if(isset($data["invite"])){
  74. if ($this->redis == false) {
  75. $this->result["ok"]=false;
  76. $this->result["message"]="no_redis_connect";
  77. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  78. return;
  79. }
  80. $redisKey = "invitecode://".$data["invite"];
  81. $code = $this->redis->exists($redisKey);
  82. if(!$code){
  83. $this->result["ok"]=false;
  84. $this->result["message"]="invite_code_invalid";
  85. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  86. return;
  87. }
  88. $data["email"] = $this->redis->get($redisKey);
  89. }else{
  90. $this->result["ok"]=false;
  91. $this->result["message"]="no_invite_code";
  92. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  93. return;
  94. }
  95. //验证用户名有效性
  96. if(!$this->isValidUsername($data["username"])){
  97. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  98. return;
  99. }
  100. //验证昵称有效性
  101. if(!$this->isValidNickName($data["nickname"])){
  102. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  103. return;
  104. }
  105. $isExist = $this->medoo->has($this->table,["username"=>$data["username"]]);
  106. if(!$isExist){
  107. if(!$this->isValidEmail($data["email"])){
  108. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  109. return;
  110. }
  111. $isExist = $this->medoo->has($this->table,["email"=>$data["email"]]);
  112. if(!$isExist){
  113. if(!$this->isValidPassword($data["password"])){
  114. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  115. return;
  116. }
  117. $data["userid"] = UUID::v4();
  118. $data["password"] = md5($data["password"]);
  119. $data["create_time"] = mTime();
  120. $data["modify_time"] = mTime();
  121. $data["setting"] = "{}";
  122. $result = $this->_create($data,["userid","username","email","password","nickname","setting","create_time","modify_time"]);
  123. if($result["ok"]){
  124. $newUserId = $this->medoo->get(
  125. $this->table,
  126. 'id',
  127. ["userid"=>$data['userid']]
  128. );
  129. $channel = new Channel($this->redis);
  130. $newChannel1 = $channel->create([
  131. "owner_uid"=>$data["userid"],
  132. "editor_id"=>$newUserId,
  133. "lang"=>$data["lang"],
  134. "name"=>$data["username"],
  135. "lang"=>$data["lang"],
  136. "status"=>30,
  137. "summary"=>""
  138. ]);
  139. $newChannel2 = $channel->create([
  140. "owner_uid"=>$data["userid"],
  141. "editor_id"=>$newUserId,
  142. "lang"=>$data["lang"],
  143. "name"=>"draft",
  144. "lang"=>$data["lang"],
  145. "status"=>10,
  146. "summary"=>""
  147. ]);
  148. echo json_encode($newChannel1, JSON_UNESCAPED_UNICODE);
  149. //删除
  150. $this->redis->del($redisKey);
  151. }else{
  152. echo json_encode($result, JSON_UNESCAPED_UNICODE);
  153. }
  154. }else{
  155. $this->result["ok"]=false;
  156. $this->result["message"]="email_is_exist";
  157. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  158. }
  159. }
  160. else{
  161. $this->result["ok"]=false;
  162. $this->result["message"]="account_is_exist";
  163. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  164. }
  165. }
  166. #发送密码重置邮件
  167. public function reset_password_send_email(){
  168. $email = $_GET["email"];
  169. $isExist = $this->medoo->has($this->table,["email"=>$email]);
  170. if($isExist){
  171. $resetToken = UUID::v4();
  172. $query = "UPDATE ".$this->table." SET reset_password_token = ? WHERE email = ? ";
  173. $stmt = $this->dbh->prepare($query);
  174. $stmt->execute(array($resetToken,$email));
  175. $ok = true;
  176. //$ok = $this->_update(["reset_password_token"=>$resetToken],["reset_password_token"],["email"=>$email]);
  177. if($ok){
  178. #send email
  179. $resetLink="https://".$_SERVER['SERVER_NAME']."/app/ucenter/reset.php?token=".$resetToken;
  180. $resetString="https://".$_SERVER['SERVER_NAME']."/app/ucenter/reset.php";
  181. // 打开文件并读取数据
  182. $irow=0;
  183. $strSubject = "";
  184. $strBody = "";
  185. if(($fp=fopen("../ucenter/reset_pwd_letter.html", "r"))!==FALSE){
  186. while(($data=fgets($fp))!==FALSE){
  187. $irow++;
  188. if($irow==1){
  189. $strSubject = $data;
  190. }else{
  191. $strBody .= $data;
  192. }
  193. }
  194. fclose($fp);
  195. }
  196. else{
  197. $this->result["ok"] = false;
  198. $this->result["message"] = "can not load email file.";
  199. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  200. return;
  201. }
  202. $strBody = str_replace("%ResetLink%",$resetLink,$strBody);
  203. $strBody = str_replace("%ResetString%",$resetString,$strBody);
  204. //TODO sendmail
  205. //Create an instance; passing `true` enables exceptions
  206. $mail = new PHPMailer(true);
  207. try {
  208. //Server settings
  209. $mail->SMTPDebug = SMTP::DEBUG_OFF; //Enable verbose debug output
  210. $mail->isSMTP(); //Send using SMTP
  211. $mail->Host = Email["Host"]; //Set the SMTP server to send through
  212. $mail->SMTPAuth = Email["SMTPAuth"]; //Enable SMTP authentication
  213. $mail->Username = Email["Username"]; //SMTP username
  214. $mail->Password = Email["Password"]; //SMTP password
  215. $mail->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS; //Enable implicit TLS encryption
  216. $mail->Port = Email["Port"]; //TCP port to connect to 465; use 587 if you have set `SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS`
  217. $mail->CharSet = 'UTF-8';
  218. $mail->Encoding = 'base64';
  219. //Recipients
  220. $mail->setFrom(Email["From"], Email["Sender"]);
  221. $mail->addAddress($email); //Add a recipient Name is optional
  222. //Content
  223. $mail->isHTML(true); //Set email format to HTML
  224. $mail->Subject = $strSubject;
  225. $mail->Body = $strBody;
  226. $mail->AltBody = $strBody;
  227. $mail->send();
  228. #邮件发送成功,修改数据库
  229. $this->_update(["reset_password_sent_at"=>Medoo::raw('datetime(<now>)')],["reset_password_sent_at"],["email"=>$email]);
  230. //邮件地址脱敏
  231. $show_email = mb_substr($email,0,2,"UTF-8") . "****" . strstr($email,"@");
  232. $this->result["message"] = 'Message has been sent to your email : ' . $show_email;
  233. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  234. return;
  235. } catch (Exception $e) {
  236. $this->result["ok"] = false;
  237. $this->result["message"] = "Message could not be sent. Mailer Error: {$mail->ErrorInfo}";
  238. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  239. return;
  240. }
  241. }else{
  242. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  243. return;
  244. }
  245. }else{
  246. $this->result["ok"]=false;
  247. $this->result["message"]="::invalid_email";
  248. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  249. }
  250. }
  251. #重置密码
  252. public function reset_password(){
  253. $json = file_get_contents('php://input');
  254. $data = json_decode($json,true);
  255. $isExist = $this->medoo->has($this->table,["username"=>$data["username"],"reset_password_token"=>$data["reset_password_token"]]);
  256. if($isExist){
  257. #reset password
  258. if(!$this->isValidPassword($data["password"])){
  259. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  260. return;
  261. }
  262. $ok = $this->_update(["password"=>md5($data["password"])],["password"],["username"=>$data["username"]]);
  263. if($ok){
  264. #成功后删除reset_password_token
  265. $ok = $this->_update(["reset_password_token"=>null,
  266. "reset_password_sent_at"=>null],
  267. null,
  268. ["username"=>$data["username"]]);
  269. }
  270. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  271. }else{
  272. $this->result["ok"]=false;
  273. $this->result["message"]="::invalid_token";
  274. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  275. }
  276. }
  277. public function signin(){
  278. $isExist = $this->medoo->has($this->table,["username"=>$_REQUEST["username"],'password'=>md5($_REQUEST["password"])]);
  279. if(!$isExist){
  280. $isExist = $this->medoo->has($this->table,["email"=>$_REQUEST["username"],'password'=>md5($_REQUEST["password"])]);
  281. if(!$isExist){
  282. $this->result["ok"]=false;
  283. $this->result["message"]="wrong username or password";
  284. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  285. }else{
  286. $uid = $this->medoo->get( $this->table, 'userid', ["email"=>$_REQUEST["username"]] );
  287. }
  288. }else{
  289. $uid = $this->medoo->get( $this->table, 'userid', ["username"=>$_REQUEST["username"]] );
  290. }
  291. //JWT
  292. $key = APP_KEY;
  293. $payload = [
  294. 'nbf' => time(),
  295. 'exp' => time()+60*60*24*365,
  296. 'uid' => $uid
  297. ];
  298. $jwt = JWT::encode($payload,$key,'HS512');
  299. //End of JWT
  300. // set cookie
  301. if(empty($_SERVER["HTTPS"])){
  302. //本地开发
  303. setcookie("user_uid", $uid,["expires"=>$ExpTime,"path"=>"/","secure"=>false,"httponly"=>true]);
  304. // setcookie("user_id", $Fetch[0]["id"], ["expires"=>$ExpTime,"path"=>"/","secure"=>false,"httponly"=>true]);
  305. setcookie("token", $jwt, ["expires"=>$ExpTime,"path"=>"/","secure"=>false,"httponly"=>true]);
  306. }else{
  307. //服务器运行
  308. setcookie("user_uid", $uid, ["expires"=>$ExpTime,"path"=>"/","secure"=>true,"httponly"=>true]);
  309. // setcookie("user_id", $Fetch[0]["id"], ["expires"=>$ExpTime,"path"=>"/","secure"=>true,"httponly"=>true]);
  310. setcookie("token", $jwt, ["expires"=>$ExpTime,"path"=>"/","secure"=>true,"httponly"=>true]);
  311. }
  312. $this->result["ok"]=true;
  313. $this->result["data"]=['token'=>$jwt];
  314. echo json_encode($this->result, JSON_UNESCAPED_UNICODE);
  315. }
  316. private function isValidPassword($password){
  317. if(mb_strlen($password,"UTF-8")<6){
  318. $this->result["ok"]=false;
  319. $this->result["message"]="::password_too_short";
  320. return false;
  321. }
  322. if(mb_strlen($password,"UTF-8")>32){
  323. $this->result["ok"]=false;
  324. $this->result["message"]="::password_too_long";
  325. return false;
  326. }
  327. if(strpos($password," ")!==false){
  328. $this->result["ok"]=false;
  329. $this->result["message"]="::password_invaild_symbol";
  330. return false;
  331. }
  332. return true;
  333. }
  334. private function isValidUsername($username){
  335. if(mb_strlen($username,"UTF-8")>32){
  336. $this->result["ok"]=false;
  337. $this->result["message"]="::username_too_long";
  338. return false;
  339. }
  340. if(mb_strlen($username,"UTF-8")<4){
  341. $this->result["ok"]=false;
  342. $this->result["message"]="::username_too_short";
  343. return false;
  344. }
  345. if(preg_match("/@|\s|\/|[A-Z]/",$username)!==0){
  346. $this->result["ok"]=false;
  347. $this->result["message"]="::username_invaild_symbol";
  348. return false;
  349. }
  350. return true;
  351. }
  352. private function isValidNickName($nickname){
  353. if(mb_strlen($nickname,"UTF-8")>32){
  354. $this->result["ok"]=false;
  355. $this->result["message"]="::nickname_too_long";
  356. return false;
  357. }
  358. if(mb_strlen($nickname,"UTF-8")<1){
  359. $this->result["ok"]=false;
  360. $this->result["message"]="::nickname_too_short";
  361. return false;
  362. }
  363. return true;
  364. }
  365. private function isValidEmail($email){
  366. $isValid = filter_var($email, FILTER_VALIDATE_EMAIL);
  367. if($isValid===false){
  368. $this->result["ok"]=false;
  369. $this->result["message"]="::invaild_email";
  370. }
  371. return $isValid;
  372. }
  373. }
  374. ?>