2023年完整教程:使用PHP和MySQL实现Android应用登录注册功能
Android的登录和注册是非常常见的场景。在我们需要用户信息的所有应用程序中,您将找到注册和登录操作。在本教程中,我们将建立一个本地Web服务器和MySQL数据库。我们将开发Android登录和注册应用程序。我们将使用PHP脚本连接到MySQL数据库。
安卓登录注册第一步是创建后端 web 服务器。我正在使用 Mac OS X,可以使用 XAMPP 快速设置本地 Apache web 服务器和 MySQL 数据库。
安装 XAMPP 服务器XAMPP(或WAMP)是一个一键安装软件,用于创建开发PHP、MySQL网页应用程序的环境(我们将和我们的安卓应用程序连接)。从这里下载并安装XAMPP。安装完成后启动XAMPP应用,将会出现以下界面。通过打开https://localhost来测试你的服务器,应该会出现以下界面。同时,你可以通过打开https://localhost/phpmyadmin来检查phpMyAdmin。让我们看一下它显示了什么!哎呀!你可能会得到类似这样的界面。似乎MySQL服务器没有正常运行。在XAMPP应用中转到“管理服务器”选项卡,然后点击“重新启动全部”。服务器应该会正常运行,就像下面的图片显示的那样。现在在localhost上测试phpMyAdmin,你会看到类似这样的界面。现在让我们测试一个简单的php脚本。创建一个新的test.php文件,然后将以下代码添加进去。
<?php
echo "Hello, World";
?>
<?php
echo "Hello, World";
?>
在上述代码中:
- ?php starts opening tag for any PHP script.
- ?> means closing tag like closing bracket in Java.
请注意:对于本教程来说,了解PHP并不是必须的。如果你使用的是MAC电脑,那么前往Applications->Xampp->htdocs。在这里创建一个新的文件夹,比如叫做test_android,并将之前创建的test.php复制粘贴到这个文件夹中。现在打开URL链接https://localhost/test_android/test.php,你将会看到一个如下的屏幕:
建立MySQL数据库通过访问https://localhost/phpmyadmin打开phpMyAdmin。现在选择顶部左侧的标题行中的 “数据库” 选项卡。给它起一个随机名称并创建。新创建的空数据库将会在左侧的侧边栏中可见。让我们在新创建的数据库中创建一个 “用户表”。在控制台中运行以下查询。
CREATE TABLE `firstDB`.`users` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`username` VARCHAR( 20 ) NOT NULL ,
`password` VARCHAR( 20 ) NOT NULL
)
CREATE TABLE `firstDB`.`users` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`username` VARCHAR( 20 ) NOT NULL ,
`password` VARCHAR( 20 ) NOT NULL
)
如果成功创建了表格,你最终会看到一个类似于这样的屏幕。
将PHP连接到MySQL数据库要将一个PHP脚本连接到MySQL数据库,需要三个输入值。以下是这些输入值及其在XAMPP服务器上的默认值。
- Host name: localhost
- MySQL user name : root
- MySQL password : It is blank. “”
让我们创建一个test-connect.php脚本,并将其添加到htdocs->test-android文件夹中。
<?php
$host="localhost";
$user="root";
$password="";
$con=mysql_connect($host,$user,$password);
if($con) {
echo '<h1>Connected to MySQL</h1>';
} else {
echo '<h1>MySQL Server is not connected</h1>';
}
?>
mysql_connect() 是 PHP 内置的连接到 MySQL 数据库的函数,使用上述参数。尝试运行 https://localhost/test_android/test-connect.php 并查看输出结果。如果连接失败,请尝试重新启动 XAMPP 服务器。
安卓登录注册应用程序
这是《使用PHP和MySQL实现Android登录与注册功能》系列教程的第2部分(共4部分)。
内容片段:在上一部分中,我们已经讨论了PHP和MySQL的基本配置。现在,让我们开始构建Android登录应用程序。我们将开发一个具有登录和注册功能的应用程序。为了确保系统的简洁性和明确性,我们将在注册过程中验证用户名和电子邮件的唯一性。在开始编写应用程序逻辑之前,让我们先准备好PHP脚本和MySQL数据库。首先,我们需要删除现有的用户表,然后为我们的应用程序创建一个全新的数据表。
CREATE TABLE IF NOT EXISTS `firstDB`.`users` (
`id` int(20) NOT NULL AUTO_INCREMENT PRIMARY KEY,
`username` varchar(70) NOT NULL,
`password` varchar(40) NOT NULL,
`email` varchar(50) NOT NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime DEFAULT NULL
)
以下是您可以复制粘贴到htdocs->test_android文件夹中的PHP脚本。config.php
<?php
define("DB_HOST", "localhost");
define("DB_USER", "root");
define("DB_PASSWORD", "");
define("DB_NAME", "firstDB");
?>
以下是用于数据库连接的脚本。db-connect.php
<?php
include_once 'config.php';
class DbConnect{
private $connect;
public function __construct(){
$this->connect = mysqli_connect(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if (mysqli_connect_errno($this->connect)){
echo "无法连接到MySQL数据库:" . mysqli_connect_error();
}
}
public function getDb(){
return $this->connect;
}
}
?>
以下脚本包含应用程序的所有核心功能。user.php
<?php
include_once 'db-connect.php';
class User{
private $db;
private $db_table = "users";
public function __construct(){
$this->db = new DbConnect();
}
public function isLoginExist($username, $password){
$query = "select * from ".$this->db_table." where username = '$username' AND password = '$password' Limit 1";
$result = mysqli_query($this->db->getDb(), $query);
if(mysqli_num_rows($result) > 0){
mysqli_close($this->db->getDb());
return true;
}
mysqli_close($this->db->getDb());
return false;
}
public function isEmailUsernameExist($username, $email){
$query = "select * from ".$this->db_table." where username = '$username' AND email = '$email'";
$result = mysqli_query($this->db->getDb(), $query);
if(mysqli_num_rows($result) > 0){
mysqli_close($this->db->getDb());
return true;
}
return false;
}
public function isValidEmail($email){
return filter_var($email, FILTER_VALIDATE_EMAIL) !== false;
}
public function createNewRegisterUser($username, $password, $email){
$isExisting = $this->isEmailUsernameExist($username, $email);
if($isExisting){
$json['success'] = 0;
$json['message'] = "注册失败。用户名/邮箱可能已存在";
}
else{
$isValid = $this->isValidEmail($email);
if($isValid)
{
$query = "insert into ".$this->db_table." (username, password, email, created_at, updated_at) values ('$username', '$password', '$email', NOW(), NOW())";
$inserted = mysqli_query($this->db->getDb(), $query);
if($inserted == 1){
$json['success'] = 1;
$json['message'] = "用户注册成功";
}else{
$json['success'] = 0;
$json['message'] = "注册失败。用户名/邮箱可能已存在";
}
mysqli_close($this->db->getDb());
}
else{
$json['success'] = 0;
$json['message'] = "注册失败。邮箱地址无效";
}
}
return $json;
}
public function loginUsers($username, $password){
$json = array();
$canUserLogin = $this->isLoginExist($username, $password);
if($canUserLogin){
$json['success'] = 1;
$json['message'] = "登录成功";
}else{
$json['success'] = 0;
$json['message'] = "用户名或密码错误";
}
return $json;
}
}
?>
在上述代码中,$json变量包含返回的JSON对象。下面的PHP脚本是应用程序首先调用的脚本。index.php
<?php
require_once 'user.php';
$username = "";
$password = "";
$email = "";
if(isset($_POST['username'])){
$username = $_POST['username'];
}
if(isset($_POST['password'])){
$password = $_POST['password'];
}
if(isset($_POST['email'])){
$email = $_POST['email'];
}
$userObject = new User();
// 注册
if(!empty($username) && !empty($password) && !empty($email)){
$hashed_password = md5($password);
$json_registration = $userObject->createNewRegisterUser($username, $hashed_password, $email);
echo json_encode($json_registration);
}
// 登录
if(!empty($username) && !empty($password) && empty($email)){
$hashed_password = md5($password);
$json_array = $userObject->loginUsers($username, $hashed_password);
echo json_encode($json_array);
}
?>
在上述代码中,我们检查电子邮件字段是否为空。如果是空的,则会调用PHP脚本中的登录函数;否则,我们将转到注册函数。JSON响应返回两个参数:成功(0或1)和消息。
- md5()函数使用RSA数据安全公司的MD5消息摘要算法来创建密码的哈希字符串。
- 为了检查邮箱地址是否有效,我们实现了isValidEmail()方法。FILTER_VALIDATE_EMAIL适用于PHP 5.2.0及以上版本。
Android登录注册项目结构
Android登录注册代码解析
在这个项目中,我们使用了三个库来实现应用程序中的HTTP调用。JSON解析器类用于执行POST和GET HTTP请求到本地主机,并以JSONObject形式返回响应。
activity_main.xml布局定义
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:fillViewport="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:paddingLeft="24dp"
android:paddingRight="24dp"
android:id="@+id/linearLayout">
<EditText android:id="@+id/editName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="用户名"
android:textColor="#FF192133"
android:textColorHint="#A0192133"
android:fontFamily="sans-serif-light"
android:focusable="true"
android:focusableInTouchMode="true" />
<EditText android:id="@+id/editPassword"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textPassword"
android:textColor="#FF192133"
android:textColorHint="#A0192133"
android:fontFamily="sans-serif-light"
android:hint="密码"
android:focusable="true"
android:focusableInTouchMode="true" />
<EditText android:id="@+id/editEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
android:textColor="#FF192133"
android:visibility="gone"
android:textColorHint="#A0192133"
android:fontFamily="sans-serif-light"
android:hint="电子邮箱"
android:focusable="true"
android:focusableInTouchMode="true" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btnSignIn"
android:text="登录"
android:textStyle="bold"
/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btnRegister"
android:text="注册"
android:textStyle="bold"
/>
</LinearLayout>
</RelativeLayout>
</ScrollView>
MainActivity.java代码
package com.Olivia.loginphpmysql;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
EditText editEmail, editPassword, editName;
Button btnSignIn, btnRegister;
String URL= "https://10.0.3.2/test_android/index.php";
JSONParser jsonParser=new JSONParser();
int i=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editEmail=(EditText)findViewById(R.id.editEmail);
editName=(EditText)findViewById(R.id.editName);
editPassword=(EditText)findViewById(R.id.editPassword);
btnSignIn=(Button)findViewById(R.id.btnSignIn);
btnRegister=(Button)findViewById(R.id.btnRegister);
btnSignIn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
AttemptLogin attemptLogin= new AttemptLogin();
attemptLogin.execute(editName.getText().toString(),editPassword.getText().toString(),"");
}
});
btnRegister.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if(i==0)
{
i=1;
editEmail.setVisibility(View.VISIBLE);
btnSignIn.setVisibility(View.GONE);
btnRegister.setText("创建账户");
}
else{
btnRegister.setText("注册");
editEmail.setVisibility(View.GONE);
btnSignIn.setVisibility(View.VISIBLE);
i=0;
AttemptLogin attemptLogin= new AttemptLogin();
attemptLogin.execute(editName.getText().toString(),editPassword.getText().toString(),editEmail.getText().toString());
}
}
});
}
private class AttemptLogin extends AsyncTask<String, String, JSONObject> {
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected JSONObject doInBackground(String... args) {
String email = args[2];
String password = args[1];
String name= args[0];
ArrayList params = new ArrayList();
params.add(new BasicNameValuePair("username", name));
params.add(new BasicNameValuePair("password", password));
if(email.length()>0)
params.add(new BasicNameValuePair("email",email));
JSONObject json = jsonParser.makeHttpRequest(URL, "POST", params);
return json;
}
protected void onPostExecute(JSONObject result) {
// dismiss the dialog once product deleted
//Toast.makeText(getApplicationContext(),result,Toast.LENGTH_LONG).show();
try {
if (result != null) {
Toast.makeText(getApplicationContext(),result.getString("message"),Toast.LENGTH_LONG).show();
} else {
Toast.makeText(getApplicationContext(), "无法从服务器检索任何数据", Toast.LENGTH_LONG).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
代码解析
这是一段相当庞大的代码!让我们从上述代码中得出重要的推理:
- https://10.0.3.2是本地回路地址。只有在使用Genymotion模拟器时才能使用该地址。使用https://10.0.2.2来对AVD模拟器进行改进。如果您是在您自己的设备上使用计算机的WIFI地址运行应用程序,请使用https://192.168.0.143。
- 点击”注册”按钮后,我们会以编程的方式隐藏”登录”按钮,并显示电子邮箱地址输入文本框。
- AttemptLogin类在后台执行对我们本地回路的网络HTTP请求。
- 用户名、密码和电子邮箱参数被添加到ArrayList中,并在JSONParser类的makeHttpRequest(URL, “POST”, params)方法中传递。
- 在onPostExecute方法中,我们将从服务器返回的消息字符串显示在一个Toast消息中。
JSONParser.java类
package com.Olivia.loginphpmysql;
import android.util.Log;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
/**
* Created by anupamchugh on 29/08/16.
*/
public class JSONParser {
static InputStream is = null;
static JSONObject jObj = null;
static JSONArray jArr = null;
static String json = "";
static String error = "";
// constructor
public JSONParser() {
}
// function get json from url
// by making HTTP POST or GET mehtod
public JSONObject makeHttpRequest(String url, String method,
ArrayList params) {
// Making HTTP request
try {
// check for request method
if(method.equals("POST")){
// request method is POST
// defaultHttpClient
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
httpPost.setEntity(new UrlEncodedFormEntity(params));
try {
Log.e("API123", " " +convertStreamToString(httpPost.getEntity().getContent()));
Log.e("API123",httpPost.getURI().toString());
} catch (Exception e) {
e.printStackTrace();
}
HttpResponse httpResponse = httpClient.execute(httpPost);
Log.e("API123",""+httpResponse.getStatusLine().getStatusCode());
error= String.valueOf(httpResponse.getStatusLine().getStatusCode());
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
}else if(method.equals("GET")){
// request method is GET
DefaultHttpClient httpClient = new DefaultHttpClient();
String paramString = URLEncodedUtils.format(params, "utf-8");
url += "?" + paramString;
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpGet);
HttpEntity httpEntity = httpResponse.getEntity();
is = httpEntity.getContent();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(
is, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
is.close();
json = sb.toString();
Log.d("API123",json);
} catch (Exception e) {
Log.e("Buffer Error", "Error converting result " + e.toString());
}
// try to parse the string to a JSON object
try {
jObj = new JSONObject(json);
jObj.put("error_code",error);
} catch (JSONException e) {
Log.e("JSON Parser", "Error parsing data " + e.toString());
}
// return JSON String
return jObj;
}
private String convertStreamToString(InputStream is) throws Exception {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line);
}
is.close();
return sb.toString();
}
}
在上述代码中,我们根据传入makeHttpRequest函数的第二个参数,调用相应的HTTPPost类或HTTPGet类。
jObj.put("error_code",error);
在上面,我们将从服务器返回的响应状态码附加在最终返回给MainActivity类的JSONObject中。注意:不要忘记在你的AndroidManifest.xml文件中添加以下权限。
<uses-permission android:name="android.permission.INTERNET"/>
很多用户在本教程的底部发布了他们的评论,表示他们收到了”无法检索数据”的提示。请注意,在Android 6.0及以上版本中,您需要在Manifest.xml文件中的应用标签中添加以下属性:android:usesCleartextTraffic=”true”。为什么要这样做呢?为了允许模拟器/设备的网络安全进行HTTP调用。请查看下面Android Q模拟器的最新截图输出。带有对AndroidManifest.xml文件进行更改的最新源代码已在链接和我们的Github存储库中更新。
应用程序运行输出结果
安卓用户注册
在下面的截图中,我们注册了一个新用户并将其添加到数据库中。然后,我们使用在注册过程中输入的凭据进行登录。

这结束了关于Android使用PHP MySQL进行登录教程的部分。您可以从下面的链接下载这个项目。它还包含一个名为test_android的文件夹,里面存放着PHP文件。请将其复制到xampp\htdocs文件夹中!祝您好运。
您还可以从我们的GitHub存储库中访问完整的源代码,请参阅下方链接。