التعامل مع PHP & Mysqli لتخزين البيانات باستخدام مكتبة Retrofit –  الجزء الاول

ساقوم في هذا الدرس بشرح تسجيل المستخدم وتسجيل الدخول في قاعدة بيانات Mysql باستخدام PHP والاعتماد على مكتبة Retrofit المقدمة من Square والموصى بها من قوقل اندرويد وتعتبر هذه المكتبة امنه وسريعة مقارنة بالمكتبات الاخرى وايضا اسرع من AsyncTask الموجود في النظام .

بالنظر الى الشكل البياني بالاسفل ستلاحظ سرعة Retrofit مقارنة بمكتبات اخرى كـVolley وايضا AsyncTask

Screen Shot 2015-10-02 at 3.24.00 AM

– متطلبات الدرس :

سنحتاج الى بعض المتطلبات للقيام بهذ الدرس والتطبيق .

  • سيرفر محلي 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 : عند الفشل بالاتصال بالسيفر .

النتيجة عند تشغيل التطبيق :

device-2015-10-04-173146

الان تمت عملية التسجيل :

– الكود كامل للـ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 من هنا .

 

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *

4 أفكار عن “التعامل مع PHP & Mysqli لتخزين البيانات باستخدام مكتبة Retrofit –  الجزء الاول”

  1. السلام عليكم ,,

    استاذ احمد اولا بشكرك على جهودك
    ثانيا لدي عدة استفسارات ملفات الـ PHP فين اضعها ؟؟
    وهل الكود بالشكل كذا كافي ؟؟ لا يحتاج الى اضافات ؟؟
    لانه مو راضي يعمل معي ؟؟

    وهل هذي تعتبر اسهل طريقة ؟؟ لاني ابحث عن طريقة لربط
    الداتا بيز mysql مع الاندرويد

  2. السلام عليكم

    استاذ احمد مممكن ايميلك

    انا عملت تطبيق للدرس ورفعت الملفات على السيرفر
    ولا يوجد اي خطا لكن ما يعمل معي ..

    فـ لو تكرمت ممكن ارسلك التطبيق وملفات الـ PHP ع الايميل
    تطلع عليه و تصحصح الخطا ,,

    شاكر لك ومقدر