I have created a flutter app which uses sql database. I have created a signup page, I want that when the user creates a new account, an email should be sent to the entered email id for verification and only after the verification the user should be able to login.
Dart Code
import 'dart:convert';
import 'dart:io';
import 'package:flutter/scheduler.dart';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:law_diary/login/login.dart';
import 'package:mailer/mailer.dart';
import 'package:mailer/smtp_server/gmail.dart';
import '../widgets/widgets.dart';
class SignUpPage extends StatefulWidget {
@override
_SignUpPageState createState() => _SignUpPageState();
}
class _SignUpPageState extends State<SignUpPage> {
TextEditingController _nameController = TextEditingController();
TextEditingController _phoneController = TextEditingController();
TextEditingController _emailController = TextEditingController();
TextEditingController _usernameController = TextEditingController();
TextEditingController _passwordController = TextEditingController();
TextEditingController _confirmPasswordController = TextEditingController();
bool _showPassword = false;
Future _signup(BuildContext cont) async {
final String name = _nameController.text.trim();
final String phone = _phoneController.text.trim();
final String email = _emailController.text.trim();
final String username = _usernameController.text.trim();
final String password = _passwordController.text.trim();
final String confirmPassword = _confirmPasswordController.text.trim();
if (name.isEmpty ||
phone.isEmpty ||
email.isEmpty ||
username.isEmpty ||
password.isEmpty ||
confirmPassword.isEmpty) {
ToastUtil.showToast("All the fields are required!");
} else {
var url =
"https://legaldiary.000webhostapp.com/android/signup/checkUser.php";
var response = await http.post(Uri.parse(url), body: {
"name": name,
"phone": phone,
"email": email,
"username": username,
"password": password,
"confirmPassword": confirmPassword,
});
print("Response from server: ${response.body}");
if (response.statusCode == 200) {
try {
var trimmedResponse = response.body.trim();
print(trimmedResponse);
var data = json.decode(trimmedResponse);
if (data["status"] == "success") {
ToastUtil.showToast(
"Account Creation Successful. Check your email for verification!");
await sendEmail();
// SchedulerBinding.instance.addPostFrameCallback((_) {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => LoginPage(),
),
);
// });
} else if (data["status"] == "error") {
ToastUtil.showToast(data["message"]);
}
} catch (e) {
print("Error parsing JSON: $e");
ToastUtil.showToast(
"An error occurred while processing the response.");
}
} else {
print("HTTP Error: ${response.statusCode}");
ToastUtil.showToast("An HTTP error occurred. Please try again later.");
}
}
}
Future<void> sendEmail() async {
// Replace these values with your actual email and SMTP server details
final String username = '[email protected]';
final String password = 'Yashi@71102';
final String recipient = _emailController.text.trim();
final smtpServer = gmail(username, password);
final message = Message()
..from = Address(username, 'Your Name')
..recipients.add(recipient)
..subject = 'Test Dart Mailer ${DateTime.now()}'
..text = 'This is a test email sent from Dart.';
try {
final sendReport = await send(message, smtpServer);
print('Message sent: ' + sendReport.toString());
} on MailerException catch (e) {
print('Message not sent. \n' + e.toString());
for (var p in e.problems) {
print('Problem: ${p.code}: ${p.msg}');
}
} on SocketException catch (e) {
print('Message not sent. \n' + e.toString());
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: CustomAppBar(),
backgroundColor: Colors.grey[200], // Greyish background
body: Stack(
children: <Widget>[
Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Color(0xFF333333), Color(0xFF666666)],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
),
Center(
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Join us now!',
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.bold,
),
),
SizedBox(height: 20),
Padding(
padding: EdgeInsets.symmetric(horizontal: 40),
child: TextFormField(
controller: _nameController,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: 'Name',
hintStyle: TextStyle(color: Colors.white70),
filled: true,
fillColor: Colors.white.withOpacity(0.1),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
),
prefixIcon: Icon(
Icons.person,
color: Colors.white,
),
),
),
),
SizedBox(height: 20),
Padding(
padding: EdgeInsets.symmetric(horizontal: 40),
child: TextFormField(
controller: _phoneController,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: 'Phone Number',
hintStyle: TextStyle(color: Colors.white70),
filled: true,
fillColor: Colors.white.withOpacity(0.1),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
),
prefixIcon: Icon(
Icons.phone,
color: Colors.white,
),
),
),
),
SizedBox(height: 20),
Padding(
padding: EdgeInsets.symmetric(horizontal: 40),
child: TextFormField(
controller: _emailController,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: 'Email',
hintStyle: TextStyle(color: Colors.white70),
filled: true,
fillColor: Colors.white.withOpacity(0.1),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
),
prefixIcon: Icon(
Icons.mail_outline,
color: Colors.white,
),
),
),
),
SizedBox(height: 20),
Padding(
padding: EdgeInsets.symmetric(horizontal: 40),
child: TextFormField(
controller: _usernameController,
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
hintText: 'Username',
hintStyle: TextStyle(color: Colors.white70),
filled: true,
fillColor: Colors.white.withOpacity(0.1),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
),
prefixIcon: Icon(
Icons.account_box,
color: Colors.white,
),
),
),
),
SizedBox(height: 20),
Padding(
padding: EdgeInsets.symmetric(horizontal: 40),
child: TextFormField(
controller: _passwordController,
style: TextStyle(color: Colors.white),
obscureText: !_showPassword,
decoration: InputDecoration(
hintText: 'Password',
hintStyle: TextStyle(color: Colors.white70),
filled: true,
fillColor: Colors.white.withOpacity(0.1),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
),
prefixIcon: Icon(
Icons.lock_outline,
color: Colors.white,
),
suffixIcon: IconButton(
icon: Icon(
_showPassword
? Icons.visibility
: Icons.visibility_off,
color: Colors.white,
),
onPressed: () {
setState(() {
_showPassword = !_showPassword;
});
},
),
),
),
),
SizedBox(height: 20),
Padding(
padding: EdgeInsets.symmetric(horizontal: 40),
child: TextFormField(
controller: _confirmPasswordController,
style: TextStyle(color: Colors.white),
obscureText: !_showPassword,
decoration: InputDecoration(
hintText: 'Confirm Password',
hintStyle: TextStyle(color: Colors.white70),
filled: true,
fillColor: Colors.white.withOpacity(0.1),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10),
borderSide: BorderSide.none,
),
prefixIcon: Icon(
Icons.lock_outline,
color: Colors.white,
),
suffixIcon: IconButton(
icon: Icon(
_showPassword
? Icons.visibility
: Icons.visibility_off,
color: Colors.white,
),
onPressed: () {
setState(() {
_showPassword = !_showPassword;
});
},
),
),
),
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
// TODO: Implement sign-up functionality
_signup(context);
},
style: ElevatedButton.styleFrom(
primary: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
'Sign Up',
style: TextStyle(
color: Colors.black87,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
),
),
SizedBox(height: 20),
GestureDetector(
onTap: () {
// Navigate back to the login page
SchedulerBinding.instance.addPostFrameCallback((_) {
Navigator.pop(context);
});
},
child: Text(
'Already have an account? Login',
style: TextStyle(
color: Colors.white,
fontSize: 16,
),
),
),
],
),
),
),
],
),
);
}
}
PHP file
<?php
header('Content-Type: application/json');
session_start();
include '../connection.php';
function checkPasswordStrength($password) {
if (preg_match('/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/', $password)) {
return 'very_strong';
} elseif (preg_match('/^(?=.*[a-z])(?=.*[A-Z]).{8,}$/', $password)) {
return 'strong';
} elseif (strlen($password) >= 8) {
return 'weak';
} else {
return 'very_weak';
}
}
function generateVerificationToken() {
return bin2hex(random_bytes(32)); // Use a secure method to generate a random token
}
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (isset($_POST['name']) && isset($_POST['phone']) && isset($_POST['email']) && isset($_POST['username'])
&& isset($_POST['password']) && isset($_POST['confirmPassword'])) {
// Get data from the POST request
$name = $_POST['name'];
$phone = $_POST['phone'];
$email = $_POST['email'];
$username = $_POST['username'];
$password = $_POST['password'];
$confirmPassword = $_POST['confirmPassword'];
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
echo json_encode(array("status" => "error", "message" => "Invalid email format."));
die();
// exit;
}
if (!preg_match('/^\d{10}$/', $phone)) {
echo json_encode(array("status" => "error", "message" => "Invalid phone number format. It should have exactly 10 digits."));
die(); // Terminate script execution
}
$conn = connectToDatabase();
// Check if email or phone number already exists
$checkEmailQuery = "SELECT * FROM userdetails WHERE email = '$email'";
$checkPhoneQuery = "SELECT * FROM userdetails WHERE phn = '$phone'";
$resultEmail = executeQuery($conn, $checkEmailQuery);
$resultPhone = executeQuery($conn, $checkPhoneQuery);
if (mysqli_num_rows($resultEmail) > 0) {
// Email is already used
echo json_encode(array("status" => "error", "message" => "Email is already registered."));
}
elseif (mysqli_num_rows($resultPhone) > 0) {
// Phone number is already used
echo json_encode(array("status" => "error", "message" => "Phone number is already registered."));
}
else {
if($password != $confirmPassword) {
echo json_encode(array("status" => "error", "message" => "Both the passwords do not match."));
die();
}
$passStrength = checkPasswordStrength($password);
// Check if the password is weak or very weak
if ($passStrength === 'weak' || $passStrength === 'very_weak') {
echo json_encode(array("status" => "error", "message" => "Password is too weak. Choose a stronger password.
\nThe password should contain at least 1 capital letter, 1 small letter, 1 digit and 1 special character.
\nThe minimum length of the password should be 8.
"));
die();
}
// Check if username already exists
$checkUsernameQuery = "SELECT * FROM userdetails WHERE username = '$username'";
$resultUsername = executeQuery($conn, $checkUsernameQuery);
if (mysqli_num_rows($resultUsername) > 0) {
// Username is already taken
echo json_encode(array("status" => "error", "message" => "Username is already taken."));
} else {
// Insert the new user record
$verificationToken = generateVerificationToken();
$insertQuery = "INSERT INTO userdetails (name, phn, username, password, email, token) VALUES ('$name', '$phone', '$username', '$password', '$email', '$verificationToken')";
if (mysqli_query($conn, $insertQuery)) {
$userId = mysqli_insert_id($conn);
// Store the token in the database
// $updateTokenQuery = "UPDATE userdetails SET token = '$verificationToken' WHERE email = '$email'";
// mysqli_query($conn, $updateTokenQuery);
// Send a verification email
// $subject = "Email Verification";
// $message = "Click the link to verify your email: http://legaldiary.000webhostapp.com/verify.php?id='.$userId.'&token='.$verificationToken";
// $headers = "From: [email protected]"; // Change this to your email
// // Use a proper mail sending function (e.g., mail())
// mail($email, $subject, $message, $headers);
// User registered successfully
echo json_encode(array("status" => "success", "message" => "Registration successful. Check your email for verification."));
} else {
// Error in registration
echo json_encode(array("status" => "error", "message" => "Error in registration."));
}
}
}
}
else {
// Return error if username or email and password are not set
echo json_encode(["error" => "All the fields are required."]);
}
}
else {
// Return error if the request method is not POST
echo json_encode(["error" => "Invalid request method. Use POST."]);
}
// Close the database connection
mysqli_close($conn);
Please help me with this. I have provided the code that I tried.
i do this in php and fluttter by adding column for the user named otp_code and another one called user_status after the user send data to signup you can generate otp code and save in the user rows then send email for the user using this function in backend without using function in flutter
and send the value of otp to user mail you recived in post method in flutter make the user go to new route with input otp field when the user write the code they recived in email resend request to handle the user if otp correct or not then change the value of status from 0 to 1