ساقوم في هذا الدرس بشرح تسجيل المستخدم وتسجيل الدخول في قاعدة بيانات Mysql باستخدام PHP والاعتماد على مكتبة Retrofit المقدمة من Square والموصى بها من قوقل اندرويد وتعتبر هذه المكتبة امنه وسريعة مقارنة بالمكتبات الاخرى وايضا اسرع من AsyncTask الموجود في النظام .
بالنظر الى الشكل البياني بالاسفل ستلاحظ سرعة Retrofit مقارنة بمكتبات اخرى كـVolley وايضا AsyncTask
– متطلبات الدرس :
سنحتاج الى بعض المتطلبات للقيام بهذ الدرس والتطبيق .
- سيرفر محلي MAMP .
- PHP 5.6
- Android Studio 1.4
- Sublime Text 3 : محرر اكواد يحتوي على بكجات لمعظم اللغات وسنتخدمة في كتابة php.
- MySqlWorkbenech : انشاء قاعدة بيانات والتعامل مع العلاقات في الجداول .
– انشاء قاعدة البيانات :
قم بانشاء قاعدة بيانات باسم users مثلا كما في الفيديو بالاسفل وانشئ جدول جديد باسم users يحتوي على حقول :
- name.
- email.
- password.
CREATE TABLE `users` ( `id` int(11) NOT NULL, `name` varchar(250) NOT NULL, `email` varchar(250) NOT NULL, `password` varchar(250) NOT NULL ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
– انشاء ملفات php :
-
انشاء ملف الاتصال :
سنقوم بانشاء ملف php للقيام بالاتصال بقاعدة البيانات مع ملاحظة اننا سنقوم باستخدام mysqli الجديدة في عملية الاتصال بحكم ان تم الاستغناء عن جميع دوال Mysql في php 5.6 .
<?php $host = 'localhost'; // default $user = 'root'; // user name for mamp $password = 'root'; // password database $db = 'store'; // database name //PHP 5.5 (New method) $connection = mysqli_connect($host, $user, $password, $db); ?>
– انشاء ملف PHP لتسجيل مستخدم جديد :
سنقوم بانشاء ملف PHP جديد للاضافة مستخدم لقاعدة بيانات Mysql وسنقوم بالتاكد من وجود المستخدم سابقا او لا بحيث لايتكرر الايميل وايضا سنقوم بتشفير كلمة المرور باستخدام API الجديدة في PHP والتي ستكون اامن من md5 بكثير واسهل في الاستخدام .
ملف php باسم singup.php :
<?php /* Code for sign up*/ require "connect.php"; //check for required fields if (isset($_POST['name']) && isset($_POST['email']) && isset($_POST['password'])) { //get data from post $name = $_POST['name']; $password = $_POST['password']; $email = $_POST['email']; // using password hash $hash = password_hash($password, PASSWORD_DEFAULT); $Vname = mysqli_query($connection, "SELECT * FROM users WHERE name='$name'"); $Vemail = mysqli_query($connection, "SELECT * FROM users WHERE email='$email' "); //check if user exist if (mysqli_num_rows($Vname) == 0) { //check if email exist if (mysqli_num_rows($Vemail) == 0) { //bulide query $insert = "INSERT INTO users (name,password,email) values('$name','$hash','$email')"; //insert to datavase $res_ins = mysqli_query($connection, $insert); //check if saved work fine if ($res_ins) { //return user info to app $post["message"] = "Registration successfull"; $post['name'] = "$name"; $post['id'] = mysqli_insert_id(); } else { //catch database error $post["message"] = $connection->error; } } else { //Email exist $post["message"] = "Email Already Exists"; } } else { //name exist $post["message"] = "Name Already Exists"; } //print JSON response echo json_encode($post); } else { // required field is missing $response["message"] = "Required fields is missing"; // print JSON response echo json_encode($response); } ?>
بالنظر الى الكود السابق فستلاحظ في البداية تم استدعاء ملف الاتصال بقاعدة البيانات وايضا التأكد من جميع الحقول المطلوبة قبل البدء في عملية الاضافة .
تم تشفير كلمة المرور باستخدام هذا السطر السيط :
$hash = password_hash($password, PASSWORD_DEFAULT);
– تجهيز مشروع اندرويد :
انشئ تطبيق اندرويد جديد وقم باضافة الاسطر التالية في gradle.bulide :
compile 'com.squareup.retrofit:retrofit:2.0.0-beta2' compile 'com.squareup.retrofit:converter-gson:2.0.0-beta2' compile 'com.squareup.okhttp:okhttp:2.5.0' compile 'com.google.code.gson:gson:2.3.1'
-
انشاء تصميم -Layout- لشاشة تسجيل الدخول :
سنقوم بانشاء شاشة تسجيل دخول وذلك باضافة
- Editext لاضافة اسم المستخدم .
- Editext للبريد الالكتروني .
- EditExt لكلمة المرور.
- Button لتنفيذ عملية التسجيل .
layout/activity_main.xml
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> </android.support.design.widget.AppBarLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="match_parent" android:layout_marginTop="?attr/actionBarSize" android:orientation="vertical" android:paddingLeft="20dp" android:paddingRight="20dp" android:paddingTop="60dp"> <ImageView android:layout_width="120dp" android:layout_height="wrap_content" android:adjustViewBounds="true" android:layout_gravity="center" android:src="@drawable/ic_account_circle_pink_500_48dp" /> <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_name" android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/input_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/hint_name" android:singleLine="true" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_email" android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/input_email" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/hint_email" android:inputType="textEmailAddress" /> </android.support.design.widget.TextInputLayout> <android.support.design.widget.TextInputLayout android:id="@+id/input_layout_password" android:layout_width="match_parent" android:layout_height="wrap_content"> <EditText android:id="@+id/input_password" android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="@string/hint_password" android:inputType="textPassword" /> </android.support.design.widget.TextInputLayout> <Button android:id="@+id/btn_signup" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="40dp" android:background="@color/colorPrimary" android:text="تسجيل" android:textColor="@android:color/white" /> </LinearLayout> </android.support.design.widget.CoordinatorLayout>
-
ملف MainActivity.class :
قبل البدء في عملية التسجيل سنقوم بمعرفة متطلبات استخدام Retrofit وهي :
- POJO (Plain Old Java Object) or Model Class : كلاس لاستقبال البيانات الراجعة من عملية Http .
- interface : للقيام بعمليات Http وهي POST,GET,PUT,DELETE ووضع رابط Http.
- Retrofit Class : سنقوم بتعريف كلاس للقيام بعملية convertor وايضا وضع رابط السيرفر الاساسي .
– انشاء POJO :
اذا نظرنا الى البيانات العائدة من ملف PHP على هيئة Json سنجد اننا نحتاج لاسترجاع message من طلب Http فبالتالي سيكون Class بهذا الشكل :
package com.tatbigy.androidretrofit; /** * Created by Ahmed on 10/4/15. * 04 * Android Retrofit */ public class Results { /** * message : Required field(s) is missing */ public Results() { } private String message; public void setMessage(String message) { this.message = message; } public String getMessage() { return message; } }
– انشاء Interface :
تعتمد Retrofit على Interface في تحويله الى Http وايضا لتعريف نوع العملية والرد من الطلب وايضا لارسال Fileds الخاصه بنا
public interface Registration { @FormUrlEncoded @POST("singup.php") Call<Results> postRegestraion(@Field("name") String name, @Field("email") String email, @Field("password") String password); }
قمنا بوضع @FormUrlEncoded وايضا عرفنا العملية بـPOST ووضعنا ملف PHP الخاص بالتسجيل .
قمنا بانشاء Call مضمن بداخلة Class Results الخاص بنا والذي قمنا بتعريفه على اساس انه البيانات الراجعة من الطلب .
ووضعنا Field المطلوبة منا بنفس المسميات في ملف PHP من حيث $_POST .
– انشاء Retrofit Class :
نحتاج للقيام بعملية Builde للـRetrofit ووضع الرابط الاساسي للسيرفر وايضا وضع Convertor الى Gson .
Retrofit registration = new Retrofit.Builder(). baseUrl("https://10.0.3.2:8888/android_retrofit/") .addConverterFactory(GsonConverterFactory.create()) .build();
الان سنقوم باستدعاء Interface الخاص بعملية التسجيل :
Registration apiService = registration.create(Registration.class);
بعد ذلك سنقوم باضافة البيانات الى Call داخل Interface :
Call<Results> reg = apiService.postRegestraion(name.getText().toString(), email.getText().toString(), password.getText().toString());
الان سنقوم بعملية الارسال الى السيرفر واسترجاع النتائج هل تمت عملية التسجيل او لا :
reg.enqueue(new Callback<Results>() { @Override public void onResponse(Response<Results> response, Retrofit retrofit) { Toast.makeText(getApplicationContext(), response.body().getMessage(), Toast.LENGTH_LONG).show(); } @Override public void onFailure(Throwable t) { // Log error here since request failed } });
نلاحظ وجود دالتين :
- onResponse : وتتم اذا نجحت عملية الاتصال بالسيرفر واعدة النتائج .
- onFailure : عند الفشل بالاتصال بالسيفر .
النتيجة عند تشغيل التطبيق :
الان تمت عملية التسجيل :
– الكود كامل للـMainActivity :
package com.tatbigy.androidretrofit; import android.os.Bundle; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; import retrofit.Call; import retrofit.Callback; import retrofit.GsonConverterFactory; import retrofit.Response; import retrofit.Retrofit; import retrofit.http.Field; import retrofit.http.FormUrlEncoded; import retrofit.http.POST; public class MainActivity extends AppCompatActivity { EditText name, email, password; Button submit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //replace actionbar with toolbar setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); name = (EditText) findViewById(R.id.input_name); email = (EditText) findViewById(R.id.input_email); password = (EditText) findViewById(R.id.input_password); submit = (Button) findViewById(R.id.btn_signup); final Retrofit registration = new Retrofit.Builder(). baseUrl("https://10.0.3.2:8888/android_retrofit/") .addConverterFactory(GsonConverterFactory.create()) .build(); submit.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Registration apiService = registration.create(Registration.class); Call<Results> reg = apiService.postRegestraion(name.getText().toString(), email.getText().toString(), password.getText().toString()); reg.enqueue(new Callback<Results>() { @Override public void onResponse(Response<Results> response, Retrofit retrofit) { Snackbar.make(name, response.body().getMessage(), Snackbar.LENGTH_LONG).show(); } @Override public void onFailure(Throwable t) { // Log error here since request failed } }); } }); } public interface Registration { @FormUrlEncoded @POST("singup.php") Call<Results> postRegestraion(@Field("name") String name, @Field("email") String email, @Field("password") String password); } }
هذه المكتبة موصى بها من Google لسرعة العمليات والحماية فيها وايضا اختصار لعملية كتابة الاكواد ومنطقيتها العالية .
جميع الملفات موجودة على GitHub من هنا .
السلام عليكم ,,
استاذ احمد اولا بشكرك على جهودك
ثانيا لدي عدة استفسارات ملفات الـ PHP فين اضعها ؟؟
وهل الكود بالشكل كذا كافي ؟؟ لا يحتاج الى اضافات ؟؟
لانه مو راضي يعمل معي ؟؟
وهل هذي تعتبر اسهل طريقة ؟؟ لاني ابحث عن طريقة لربط
الداتا بيز mysql مع الاندرويد
السلام عليكم
ساقوم باضافة الجزء الاخير من الدرس مع جميع الملفات
اسف ع التاخير
السلام عليكم
استاذ احمد مممكن ايميلك
انا عملت تطبيق للدرس ورفعت الملفات على السيرفر
ولا يوجد اي خطا لكن ما يعمل معي ..
فـ لو تكرمت ممكن ارسلك التطبيق وملفات الـ PHP ع الايميل
تطلع عليه و تصحصح الخطا ,,
شاكر لك ومقدر
السلام عليكم وين الفيديو ليس موجود