Flutter Contact Form Using MySQL & PHP
By Webotapp Academy•
<!-- wp:paragraph -->\n<p>In this article, we have three tasks:</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true} -->\n<ol><!-- wp:list-item -->\n<li>Create SQL Table</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>Create Flutter Screen</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>Create PHP Api </li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">Part 1: Create SQL Table</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>You can create a table named <code>contact</code> with the specified fields using the following SQL code:</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code>CREATE TABLE contact (\n id INT PRIMARY KEY,\n con_name TEXT,\n con_mobile TEXT,\n con_email TEXT,\n con_message TEXT\n);</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>This SQL code creates a table with the following columns:</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list -->\n<ul><!-- wp:list-item -->\n<li><code>id</code>: An auto-incremented primary key field of integer type.</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li><code>con_name</code>: A text field for contact names.</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li><code>con_mobile</code>: A text field for contact mobile numbers.</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li><code>con_email</code>: A text field for contact email addresses.</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li><code>con_message</code>: A long text field for contact messages or comments.</li>\n<!-- /wp:list-item --></ul>\n<!-- /wp:list -->\n\n<!-- wp:paragraph -->\n<p>You can execute this SQL code in your database management system to create the <code>contact</code> table with the specified structure.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">Part 2: Create a Flutter Screen</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>Let's break down the Flutter screen for a contact form step by step:</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true} -->\n<ol><!-- wp:list-item -->\n<li>Import Statements:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> import 'package:flutter/material.dart';\n import 'package:http/http.dart' as http;</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>The code starts by importing the necessary Flutter and HTTP packages.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":2} -->\n<ol start=\"2\"><!-- wp:list-item -->\n<li>Widget Class:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> class Contact extends StatefulWidget {\n const Contact({Key? key}) : super(key: key);\n\n @override\n _ContactState createState() => _ContactState();\n }</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>This is a typical Flutter widget class that represents the contact form. It extends <code>StatefulWidget</code> and has a state class associated with it.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":3} -->\n<ol start=\"3\"><!-- wp:list-item -->\n<li>State Class:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> class _ContactState extends State<Contact> {</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>Here, the state class <code>_ContactState</code> is defined, which contains the logic and content of the contact form.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":4} -->\n<ol start=\"4\"><!-- wp:list-item -->\n<li>Text Editing Controllers:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> final TextEditingController nameController = TextEditingController();\n final TextEditingController mobileController = TextEditingController();\n final TextEditingController emailController = TextEditingController();\n final TextEditingController messageController = TextEditingController();</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>Four text editing controllers are created to manage the input data for name, mobile, email, and message fields.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":5} -->\n<ol start=\"5\"><!-- wp:list-item -->\n<li><code>submitForm</code> Method:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> Future<void> submitForm() async {\n // ...\n }</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>The <code>submitForm</code> method is defined as an asynchronous function. This method will handle the submission of the contact form data to the server via HTTP.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":6} -->\n<ol start=\"6\"><!-- wp:list-item -->\n<li>Scaffold Widget:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> return Scaffold(\n appBar: AppBar(\n title: Text('Contact Us'),\n backgroundColor: Colors.pink,\n ),\n body: SingleChildScrollView(\n child: Padding(\n padding: const EdgeInsets.all(16.0),\n child: Column(\n children: [\n // Form fields go here\n ],\n ),\n ),\n ),\n );</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>The <code>Scaffold</code> widget is used to create the basic structure of the screen. It includes an app bar with the title \"Contact Us.\" The main content is placed inside a <code>SingleChildScrollView</code> to allow scrolling if the content overflows.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":7} -->\n<ol start=\"7\"><!-- wp:list-item -->\n<li>Form Fields:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> TextFormField(\n controller: nameController,\n decoration: InputDecoration(\n labelText: 'Name',\n border: OutlineInputBorder(\n borderRadius: BorderRadius.circular(10),\n ),\n ),\n ),</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>A <code>TextFormField</code> widget is used for each form field (Name, Mobile, Email, and Message). It includes a controller for managing the input, a label, and a border for styling.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list -->\n<ul><!-- wp:list-item -->\n<li>The Name field accepts the user's name.</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>The Mobile field accepts a 10-digit mobile number with a number keyboard.</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>The Email field accepts an email address with the email keyboard.</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>The Message field is a multi-line text input for the user's message.</li>\n<!-- /wp:list-item --></ul>\n<!-- /wp:list -->\n\n<!-- wp:list {\"ordered\":true} -->\n<ol><!-- wp:list-item -->\n<li>Submit Button:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> ElevatedButton(\n onPressed: submitForm,\n child: Text('Submit'),\n ),</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>An <code>ElevatedButton</code> is provided for submitting the form. When clicked, it triggers the <code>submitForm</code> method.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Overall, this Flutter screen creates a contact form with text input fields for the user's name, mobile number, email address, and message. Upon clicking the \"Submit\" button, the form data is sent to the specified API endpoint using the HTTP POST method. Any response from the server is logged for further handling.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p></p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p><strong>Full Source Code</strong></p>\n<!-- /wp:paragraph -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code>import 'package:flutter/material.dart';\nimport 'package:http/http.dart' as http;\n\nclass Contact extends StatefulWidget {\n const Contact({Key? key}) : super(key: key);\n\n @override\n _ContactState createState() => _ContactState();\n}\n\nclass _ContactState extends State<Contact> {\n final TextEditingController nameController = TextEditingController();\n final TextEditingController mobileController = TextEditingController();\n final TextEditingController emailController = TextEditingController();\n final TextEditingController messageController = TextEditingController();\n\n Future<void> submitForm() async {\n final url = Uri.parse('https://booppers.tk/api/contact.php');\n\n final response = await http.post(\n url,\n body: {\n 'con_name': nameController.text,\n 'con_mobile': mobileController.text,\n 'con_email': emailController.text,\n 'con_message': messageController.text,\n },\n );\n\n if (response.statusCode == 200) {\n // Form submitted successfully. You can handle the response here.\n print('Response: ${response.body}');\n } else {\n // Form submission failed. Handle the error.\n print('Error: ${response.reasonPhrase}');\n }\n }\n\n @override\n Widget build(BuildContext context) {\n return Scaffold(\n appBar: AppBar(\n title: Text('Contact Us'),\n backgroundColor: Colors.pink,\n ),\n body: SingleChildScrollView(\n child: Padding(\n padding: const EdgeInsets.all(16.0),\n child: Column(\n children: [\n TextFormField(\n controller: nameController,\n decoration: InputDecoration(\n labelText: 'Name',\n border: OutlineInputBorder(\n borderRadius: BorderRadius.circular(10),\n ),\n ),\n ),\n SizedBox(height: 10),\n TextFormField(\n controller: mobileController,\n decoration: InputDecoration(\n labelText: 'Mobile (10 digits)',\n border: OutlineInputBorder(\n borderRadius: BorderRadius.circular(10),\n ),\n ),\n keyboardType: TextInputType.number,\n ),\n SizedBox(height: 10),\n TextFormField(\n controller: emailController,\n decoration: InputDecoration(\n labelText: 'Email',\n border: OutlineInputBorder(\n borderRadius: BorderRadius.circular(10),\n ),\n ),\n keyboardType: TextInputType.emailAddress,\n ),\n SizedBox(height: 10),\n TextFormField(\n controller: messageController,\n decoration: InputDecoration(\n labelText: 'Message',\n border: OutlineInputBorder(\n borderRadius: BorderRadius.circular(10),\n ),\n ),\n maxLines: 5,\n ),\n SizedBox(height: 20),\n ElevatedButton(\n onPressed: submitForm,\n child: Text('Submit'),\n ),\n ],\n ),\n ),\n ),\n );\n }\n}\n</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:heading -->\n<h2 class=\"wp-block-heading\">Part 3: Create PHP API</h2>\n<!-- /wp:heading -->\n\n<!-- wp:paragraph -->\n<p>Let's break down the PHP code for handling a contact form submission step by step:</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true} -->\n<ol><!-- wp:list-item -->\n<li>Include Statements:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> include('cors.php'); // Include CORS headers if needed\n include('../database.php'); // Include your database connection</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>The code starts by including necessary files, including CORS headers and the database connection file.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":2} -->\n<ol start=\"2\"><!-- wp:list-item -->\n<li>Header for JSON Response:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> header('Content-Type: application/json');</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>This sets the response content type as JSON, indicating that the server will respond with JSON data.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":3} -->\n<ol start=\"3\"><!-- wp:list-item -->\n<li>Initialize Response Array:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> $response = array();</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>An empty associative array, <code>$response</code>, is initialized to store the response data.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":4} -->\n<ol start=\"4\"><!-- wp:list-item -->\n<li>Try-Catch Block for Error Handling:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> try {\n // Code for handling the request and database interaction goes here\n } catch (Exception $e) {\n $response['success'] = false;\n $response['message'] = $e->getMessage();\n }</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>The code is wrapped in a try-catch block to handle exceptions. If an error occurs at any point, it's caught and an error response is generated.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":5} -->\n<ol start=\"5\"><!-- wp:list-item -->\n<li>Request Method Check:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> if ($_SERVER['REQUEST_METHOD'] === 'POST') {\n // ...\n } else {\n throw new Exception(\"Invalid request method.\");\n }</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>This part checks if the request method is POST. It ensures that the code only proceeds if the request is a POST request. If it's not, an exception is thrown.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":6} -->\n<ol start=\"6\"><!-- wp:list-item -->\n<li>Data Validation:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> if (empty($con_name) || empty($con_mobile) || empty($con_email) || empty($con_message)) {\n throw new Exception(\"All fields are required.\");\n }</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>Input data validation is performed to ensure that all required fields (Name, Mobile, Email, and Message) are not empty. If any field is empty, an exception is thrown to handle this error.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>You can add more validation for mobile number and email format if needed to ensure data integrity.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":7} -->\n<ol start=\"7\"><!-- wp:list-item -->\n<li>Database Query:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> $sql = \"INSERT INTO contact (con_name, con_mobile, con_email, con_message) VALUES (:con_name, :con_mobile, :con_email, :con_message)\";\n $stmt = $conn->prepare($sql);</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>A SQL query is prepared to insert the contact data into the database table \"contact.\" A prepared statement is used for security and efficiency.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":8} -->\n<ol start=\"8\"><!-- wp:list-item -->\n<li>Binding Parameters:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> $stmt->bindParam(':con_name', $con_name);\n $stmt->bindParam(':con_mobile', $con_mobile);\n $stmt->bindParam(':con_email', $con_email);\n $stmt->bindParam(':con_message', $con_message);</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>The parameters are bound to the prepared statement to securely insert the data.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":9} -->\n<ol start=\"9\"><!-- wp:list-item -->\n<li>Database Execution and Response:</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code> if ($stmt->execute()) {\n $response['success'] = true;\n $response['message'] = \"Data inserted successfully.\";\n } else {\n throw new Exception(\"Database query failed: \" . $stmt->errorInfo());\n }</code></pre>\n<!-- /wp:code -->\n\n<!-- wp:paragraph -->\n<p>The query is executed. If the execution is successful, a success response is generated. If there's an issue with the database query, an exception is thrown, and the error message is included in the response.</p>\n<!-- /wp:paragraph -->\n\n<!-- wp:list {\"ordered\":true,\"start\":10} -->\n<ol start=\"10\"><!-- wp:list-item -->\n<li>Error Handling: <code>} catch (Exception $e) { $response['success'] = false; $response['message'] = $e->getMessage(); }</code> If any errors occur during the process, they are caught, and the response is set to indicate failure with an error message.</li>\n<!-- /wp:list-item -->\n\n<!-- wp:list-item -->\n<li>JSON Response: <code>echo json_encode($response);</code> Finally, the response data, whether it's a success message or an error message, is encoded as JSON and sent as the HTTP response. This allows the client-side application to handle the response appropriately.</li>\n<!-- /wp:list-item --></ol>\n<!-- /wp:list -->\n\n<!-- wp:paragraph -->\n<p><strong>Full Source Code:</strong></p>\n<!-- /wp:paragraph -->\n\n<!-- wp:code -->\n<pre class=\"wp-block-code\"><code><?php\ninclude('cors.php'); // Include CORS headers if needed\ninclude('../database.php'); // Include your database connection\n\nheader('Content-Type: application/json');\n\n// Initialize an empty response array.\n$response = array();\n\ntry {\n // Check if the request is a POST request.\n if ($_SERVER['REQUEST_METHOD'] === 'POST') {\n // Get data from the POST request.\n $con_name = $_POST['con_name'];\n $con_mobile = $_POST['con_mobile'];\n $con_email = $_POST['con_email'];\n $con_message = $_POST['con_message'];\n\n // Validate input data\n if (empty($con_name) || empty($con_mobile) || empty($con_email) || empty($con_message)) {\n throw new Exception(\"All fields are required.\");\n }\n\n // Add more validation for mobile number and email format if needed\n\n // Create a SQL query to insert the contact data into your database.\n $sql = \"INSERT INTO contact (con_name, con_mobile, con_email, con_message) VALUES (:con_name, :con_mobile, :con_email, :con_message)\";\n $stmt = $conn->prepare($sql);\n\n // Bind the parameters.\n $stmt->bindParam(':con_name', $con_name);\n $stmt->bindParam(':con_mobile', $con_mobile);\n $stmt->bindParam(':con_email', $con_email);\n $stmt->bindParam(':con_message', $con_message);\n\n if ($stmt->execute()) {\n $response['success'] = true;\n $response['message'] = \"Data inserted successfully.\";\n } else {\n throw new Exception(\"Database query failed: \" . $stmt->errorInfo());\n }\n } else {\n throw new Exception(\"Invalid request method.\");\n }\n} catch (Exception $e) {\n $response['success'] = false;\n $response['message'] = $e->getMessage();\n}\n\n// Output the response as JSON.\necho json_encode($response);\n?>\n</code></pre>\n<!-- /wp:code -->