In this example, We have shown a fully functional login panel in flutter and validate using PHP and MySQL as back end. The panel shows an error message on error and progress indicator on the “login” button click. Here, I have used the REST API to communicate with the Server.
Our Database:
This is the table user list, where the password is md5()
encrypted string. The PHP code is given below: test/login.php
<?php
$db = "test_db"; //database name
$dbuser = "root"; //database username
$dbpassword = "root"; //database password
$dbhost = "localhost"; //database host
$return["error"] = false;
$return["message"] = "";
$return["success"] = false;
$link = mysqli_connect($dbhost, $dbuser, $dbpassword, $db);
if(isset($_POST["username"]) && isset($_POST["password"])){
//checking if there is POST data
$username = $_POST["username"];
$password = $_POST["password"];
$username = mysqli_real_escape_string($link, $username);
//escape inverted comma query conflict from string
$sql = "SELECT * FROM user_list WHERE username = '$username'";
//building SQL query
$res = mysqli_query($link, $sql);
$numrows = mysqli_num_rows($res);
//check if there is any row
if($numrows > 0){
//is there is any data with that username
$obj = mysqli_fetch_object($res);
//get row as object
if(md5($password) == $obj->password){
$return["success"] = true;
$return["uid"] = $obj->user_id;
$return["fullname"] = $obj->fullname;
$return["address"] = $obj->address;
}else{
$return["error"] = true;
$return["message"] = "Your Password is Incorrect.";
}
}else{
$return["error"] = true;
$return["message"] = 'No username found.';
}
}else{
$return["error"] = true;
$return["message"] = 'Send all parameters.';
}
mysqli_close($link);
header('Content-Type: application/json');
// tell browser that its a json data
echo json_encode($return);
//converting array to JSON string
?>
Now in Flutter, you have to add http Flutter package in your dependency by adding the following like in pubspec.yaml
dependencies:
flutter:
sdk: flutter
http: ^0.13.1
Add Internet Permission by adding this line in android/app/src/main/AndroidManifest.xml before <application>
<uses-permission android:name="android.permission.INTERNET"/>
Now, Login Panel Dart Code:
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
//import http package manually
class LoginPage extends StatefulWidget{
@override
State<StatefulWidget> createState() {
return _LoginPage();
}
}
class _LoginPage extends State<LoginPage>{
String errormsg;
bool error, showprogress;
String username, password;
var _username = TextEditingController();
var _password = TextEditingController();
startLogin() async {
String apiurl = "http://192.168.0.112/test/login.php"; //api url
//dont use http://localhost , because emulator don't get that address
//insted use your local IP address or use live URL
//hit "ipconfig" in windows or "ip a" in linux to get you local IP
print(username);
var response = await http.post(Uri.parse(apiurl), body: {
'username': username, //get the username text
'password': password //get password text
});
if(response.statusCode == 200){
var jsondata = json.decode(response.body);
if(jsondata["error"]){
setState(() {
showprogress = false; //don't show progress indicator
error = true;
errormsg = jsondata["message"];
});
}else{
if(jsondata["success"]){
setState(() {
error = false;
showprogress = false;
});
//save the data returned from server
//and navigate to home page
String uid = jsondata["uid"];
String fullname = jsondata["fullname"];
String address = jsondata["address"];
print(fullname);
//user shared preference to save data
}else{
showprogress = false; //don't show progress indicator
error = true;
errormsg = "Something went wrong.";
}
}
}else{
setState(() {
showprogress = false; //don't show progress indicator
error = true;
errormsg = "Error during connecting to server.";
});
}
}
@override
void initState() {
username = "";
password = "";
errormsg = "";
error = false;
showprogress = false;
//_username.text = "defaulttext";
//_password.text = "defaultpassword";
super.initState();
}
@override
Widget build(BuildContext context) {
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: Colors.transparent
//color set to transperent or set your own color
));
return Scaffold(
body: SingleChildScrollView(
child:Container(
constraints: BoxConstraints(
minHeight:MediaQuery.of(context).size.height
//set minimum height equal to 100% of VH
),
width:MediaQuery.of(context).size.width,
//make width of outer wrapper to 100%
decoration:BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topRight,
end: Alignment.bottomLeft,
colors: [ Colors.orange,Colors.deepOrangeAccent,
Colors.red, Colors.redAccent,
],
),
), //show linear gradient background of page
padding: EdgeInsets.all(20),
child:Column(children:<Widget>[
Container(
margin: EdgeInsets.only(top:80),
child: Text("Sign Into System", style: TextStyle(
color:Colors.white,fontSize: 40, fontWeight: FontWeight.bold
),), //title text
),
Container(
margin: EdgeInsets.only(top:10),
child: Text("Sign In using Email and Password", style: TextStyle(
color:Colors.white,fontSize: 15
),), //subtitle text
),
Container(
//show error message here
margin: EdgeInsets.only(top:30),
padding: EdgeInsets.all(10),
child:error? errmsg(errormsg):Container(),
//if error == true then show error message
//else set empty container as child
),
Container(
padding: EdgeInsets.fromLTRB(10,0,10,0),
margin: EdgeInsets.only(top:10),
child: TextField(
controller: _username, //set username controller
style:TextStyle(color:Colors.orange[100], fontSize:20),
decoration: myInputDecoration(
label: "Username",
icon: Icons.person,
),
onChanged: (value){
//set username text on change
username = value;
},
),
),
Container(
padding: EdgeInsets.all(10),
child: TextField(
controller: _password, //set password controller
style: TextStyle(color:Colors.orange[100], fontSize:20),
obscureText: true,
decoration: myInputDecoration(
label: "Password",
icon: Icons.lock,
),
onChanged: (value){
// change password text
password = value;
},
),
),
Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(top:20),
child: SizedBox(
height: 60, width: double.infinity,
child:RaisedButton(
onPressed: (){
setState(() {
//show progress indicator on click
showprogress = true;
});
startLogin();
},
child: showprogress?
SizedBox(
height:30, width:30,
child: CircularProgressIndicator(
backgroundColor: Colors.orange[100],
valueColor: AlwaysStoppedAnimation<Color>(Colors.deepOrangeAccent),
),
):Text("LOGIN NOW", style: TextStyle(fontSize: 20),),
// if showprogress == true then show progress indicator
// else show "LOGIN NOW" text
colorBrightness: Brightness.dark,
color: Colors.orange,
shape: RoundedRectangleBorder(
borderRadius:BorderRadius.circular(30)
//button corner radius
),
),
),
),
Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(top:20),
child: InkResponse(
onTap:(){
//action on tap
},
child:Text("Forgot Password? Troubleshoot",
style: TextStyle(color:Colors.white, fontSize:18),
)
),
)
]),
)
),
);
}
InputDecoration myInputDecoration({String label, IconData icon}){
return InputDecoration(
hintText: label, //show label as placeholder
hintStyle: TextStyle(color:Colors.orange[100], fontSize:20), //hint text style
prefixIcon: Padding(
padding: EdgeInsets.only(left:20, right:10),
child:Icon(icon, color: Colors.orange[100],)
//padding and icon for prefix
),
contentPadding: EdgeInsets.fromLTRB(30, 20, 30, 20),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide(color:Colors.orange[300], width: 1)
), //default border of input
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(30),
borderSide: BorderSide(color:Colors.orange[200], width: 1)
), //focus border
fillColor: Color.fromRGBO(251,140,0, 0.5),
filled: true, //set true if you want to show input background
);
}
Widget errmsg(String text){
//error message widget.
return Container(
padding: EdgeInsets.all(15.00),
margin: EdgeInsets.only(bottom: 10.00),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30),
color: Colors.red,
border: Border.all(color:Colors.red[300], width:2)
),
child: Row(children: <Widget>[
Container(
margin: EdgeInsets.only(right:6.00),
child: Icon(Icons.info, color: Colors.white),
), // icon for error message
Text(text, style: TextStyle(color: Colors.white, fontSize: 18)),
//show error message text
]),
);
}
}
Study the example, and learn how to make the Login Panel and validate the form using PHP and MySQL at the server-side.
Please Wait...
5 Comments on this Article
rk reza
signup page code please
sergannn
Amazing - very easy to understand.
How do you think, is it a very out-dated (deprecated) way?
Niranjan dahal
Thanks a lot to the point , i already knew php mysqli but don’t have idea to use with flutter , you fully helped me
Jerico
Why i’m getting this error when i clicked on the button?
’FormatException (FormatException: Unexpected character (at character 1)’
Help please, thanks!
Hari Prasad Chaudhary
Hello Jerico, Please check your API response with POSTMAN, it is due to, there is some error in the PHP code, and your response with error message HTML, so there is an unexpected character due to invalid JSON.
1 year ago