ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Android PHP MySQL 예제 - 데이터베이스에 데이터 입력하기
    Android/Android PHP MySQL 예제 2019. 11. 17. 18:26




    안드로이드 앱이  PHP 프로그램을 매개로 하여 MySQL 데이터베이스 서버에 데이터를 저장하는 간단한 예제입니다. 



    1. Apache2, MySQL, PHP7 설치

    2. 데이터베이스 및 테이블 생성

    3. 웹브라우저로 PHP 동작  테스트

    4. Android 앱에서 테스트

    5. 코드 설명

    6. 관련 포스팅

    7. 참고


    최초 작성 2015. 11. 21

    최종 작성 2019. 11. 17 androidx 사용하도록 변경



    안드로이드 앱에서 바로 MySQL에 접속한다면 구현이 간단할 수 있습니다.

    하지만 리버스 엔지니어링을 통해 안드로이드 앱에서 소스코드를 추출하게 되면 서버 아이피와 MySQL 서버 접속용 아이디와 패스워드가 유출될 수 있습니다. 


    그래서 웹서버에서 실행되는 PHP를 이용하여 진행하게 됩니다.  안드로이드 앱의 코드를 추출한다 해도 서버 IP와 실행되는 PHP 파일 이름만 알 수 있습니다. 

    하지만 해당 IP와 PHP 파일에 대한 정보를 통해 악용할 수도 있기 때문에 추가로 필요한 작업이 있을 수도 있을 듯하지만 제가 아는 범위에서 벗어나서 논외로 합니다. 

     



    1. Apache2, MySQL, PHP7 설치

    서버로 사용하려는 운영체제에 따라 1-1 또는 1-2를 진행하세요.

    1-1. WIndows

    다음 포스팅을 참고하여 윈도우에 WAMP( Apache2, MySQL , PHP7)를 설치합니다. 



    윈도우 기반 웹 개발 환경 만들기 ( Apache2, PHP, MySQL, PhpMyAdmin )

    http://webnautes.tistory.com/1206 




    오른쪽 아래 시계 옆에 있는 WampServer 트레이 아이콘을 마우스 왼쪽 버튼으로 클릭한 후, 메뉴에서 PHP > Version을 선택합니다. 


    사용가능한 PHP 버전이 보이는 데 최신 버전인 7.2.18를 선택합니다. 글 작성시점과 버전이 다를 수 있습니다. 





    1-2. Ubuntu

    다음 포스팅을 참고하여 Ubuntu에  LAMP( Apache2, MySQL , PHP7)를 설치합니다. 



    Ubuntu 18.04에 LAMP ( Apache2, MySQL , PHP7) 설치하는 방법

    http://webnautes.tistory.com/1185    





    2. 데이터베이스 및 테이블 생성 


    2-1. MySQL에서 데이터베이스를 새로 생성하고  해당 데이베이스를 접근할 수 있는 사용자를 추가하는 방법을 설명합니다. 


    서버 컴퓨터의 운영체제가 Windows라면 2-2, Ubuntu라면 2-3을 진행하세요.




    2-2. 오른쪽 아래 시계 옆에 있는 WampServer 트레이 아이콘을 마우스 왼쪽 버튼으로 클릭한 후, 메뉴에서 MySQL > MySQL console을 선택합니다. 


    로그인 사용자로 root가 지정되어 있습니다. OK 버튼을 클릭합니다. 




    Enter password: 라는 메시지가 보입니다.  설치시 설정해주었던 root 암호를 입력해주면 로그인이 완료됩니다. 


    root 암호를 설정한 적이 없다면 엔터를 입력하여 진행할 수도 있지만 포스팅의 1-1을 다시 진행하여 root 암호를 부여해주세요.. 



    이제 2-4를 진행하세요.




    2-3. Ubuntu 18.04에서 설치한 MySQL에서는 디폴트로 auth_socket 플러그인을 사용하기 때문에 기존에 사용하던 방법(root 계정의 암호입력)으로 로그인이 되지 않습니다. 


    확인을 못해봤는데 Ubuntu 16.04에서 최신 버전 MySQL을 사용한다면 같은 상황이 있을 수 있습니다. 


    webnautes@webnautes-pc:~$ mysql -u root -p
    Enter password:
    ERROR 1698 (28000): Access denied for user 'root'@'localhost'



    sudo 명령시 입력하는 사용자 암호 입력으로 기존 로그인을 대체합니다.


    webnautes@webnautes-pc:~$ sudo mysql
    [sudo] webnautes의 암호:
    Welcome to the MySQL monitor.  Commands end with ; or \g.
    Your MySQL connection id is 14
    Server version: 5.7.22-0ubuntu18.04.1 (Ubuntu)

    Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

    Oracle is a registered trademark of Oracle Corporation and/or its
    affiliates. Other names may be trademarks of their respective
    owners.

    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.


    mysql>




    2-4. 윈도우와 우분투에서 동일하게 진행하는 부분입니다.


    데이터베이스를 생성합니다. 


    mysql> create database 데이터베이스이름 DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;


    mysql> create database testdb default character set utf8;

    Query OK, 1 row affected (0.00 sec)



    새로 생성한 데이터베이스를 사용할 사용자를 생성합니다. 


    mysql> create user 사용자이름 identified by '패스워드';


    mysql> create user webnautes identified by 'apple9!';

    Query OK, 0 rows affected (0.01 sec)



    앞에서 생성했던 데이터베이스를 새로 생성한 사용자가 사용하도록 권한을 부여합니다.  


    mysql> GRANT ALL PRIVILEGES ON 데이터베이스이름.* TO '사용자이름'@'localhost' identified by '패스워드';


    mysql> grant all privileges on testdb.* to 'webnautes'@'localhost' identified by 'apple9!';

    Query OK, 0 rows affected, 1 warning (0.00 sec)



    quit를 입력하여 MySQL 콘솔을 종료합니다.




    2-5.  MySQL 콘솔에 새로 생성한 사용자로 접속합니다. 


    우분투에서는 다음처럼 MySQL 로그인을 합니다. 사용자 이름은 새로 생성한 데이터베이스 접근권한을 가진 사용자 입니다. 

    Enter password: 에 사용자의 암호를 입력해줍니다. 


    $ mysql -u 사용자이름 -p

    Enter password:



    윈도우에서는 오른쪽 아래 시계 옆에 있는 WampServer 트레이 아이콘을 마우스 왼쪽 버튼으로 클릭한 후, 메뉴에서 MySQL > MySQL console을 선택합니다.


    새로 생성한 데이터베이스 접근권한을 가진 사용자 이름을 적고 OK 버튼을 클릭합니다. 




    Enter password: 메시지가 보이면 사용자의 암호를 입력해줍니다. 


    Enter password:




    2-6. 데이터베이스 testdb에 필요한 테이블 person을 생성하고  MySQL이 잘 동작하는지 여부를 다음처럼 확인합니다. 


    앞에서 생성해두었던 데이터베이스 testdb가 보입니다.

    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | testdb             |
    +--------------------+
    2 rows in set (0.00 sec)


    데이터베이스 testdb를 사용하도록 하고

    mysql> use testdb;
    Database changed



    다음 명령을 복사 후 붙여넣기 해서 person 테이블을 생성합니다.

    create table person(
          id bigint(20) unsigned not null auto_increment,
          name varchar(255) not null,
          country varchar(255) not null,
          primary key (id)
    )  DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;


    mysql> create table person(
        ->     id bigint(20) unsigned not null auto_increment,
        ->     name varchar(255) not null,
        ->     country varchar(255) not null,
        ->     primary key (id)
        -> )  DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
    Query OK, 0 rows affected (0.03 sec)


    person 테이블이 생성되었습니다.


    mysql> show tables;
    +--------------+
    | Tables_in_db |
    +--------------+
    | person       |
    +--------------+
    1 row in set (0.00 sec)


    데이터 하나를 테이블에 입력 해봅니다. 


    mysql> insert into person(name, country) values('test', 'test');
    Query OK, 1 row affected (0.00 sec)


    쿼리를 해서 데이터를 다시 가져와 봅니다.

     
    mysql> select * from person;
    +----+------+---------+
    | id | name | country |
    +----+------+---------+
    |  1 | test | test    |
    +----+------+---------+
    1 row in set (0.00 sec)


    person 테이블의 데이터를 초기화합니다. 


    mysql> truncate person;
    Query OK, 0 rows affected (0.01 sec)


    테이블이 초기화 되었습니다.


    mysql> select * from person;

    Empty set (0.00 sec)


    MySQL 콘솔을 종료합니다.


    mysql> exit
    Bye




    3. 웹브라우저로 PHP 동작  테스트

    Android 앱으로 테스트를  진행하기 전에 다음 PHP 코드를  웹 브라우저로 간단한 테스트를 해보겠습니다.


    다음 두 개의 파일이 필요합니다.

    dbcon.php

    MySQL 서버 접속을 위해 사용되는 코드입니다. 


    insert.php

    지정해 높은 데이터베이스의 테이블에 데이터를 저장하기 위해 사용됩니다.



    dbcon.php


    <?php

        $host = 'localhost';
        $username = 'webnautes'; # MySQL 계정 아이디
        $password = 'apple9!'; # MySQL 계정 패스워드
        $dbname = 'testdb'# DATABASE 이름


        $options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
       
        try {

            $con = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8",$username, $password);
        } catch(PDOException $e) {

            die("Failed to connect to the database: " . $e->getMessage());
        }


        $con->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        $con->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

        if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
            function undo_magic_quotes_gpc(&$array) {
                foreach($array as &$value) {
                    if(is_array($value)) {
                        undo_magic_quotes_gpc($value);
                    }
                    else {
                        $value = stripslashes($value);
                    }
                }
            }

            undo_magic_quotes_gpc($_POST);
            undo_magic_quotes_gpc($_GET);
            undo_magic_quotes_gpc($_COOKIE);
        }

        header('Content-Type: text/html; charset=utf-8');
        #session_start();
    ?>




    insert.php


    <?php

        error_reporting(E_ALL);
        ini_set('display_errors',1);

        include('dbcon.php');


        if( ($_SERVER['REQUEST_METHOD'] == 'POST') && isset($_POST['submit']))
        {

            $name=$_POST['name'];
            $country=$_POST['country'];

            if(empty($name)){
                $errMSG = "이름을 입력하세요.";
            }
            else if(empty($country)){
                $errMSG = "나라를 입력하세요.";
            }

            if(!isset($errMSG))
            {
                try{
                    $stmt = $con->prepare('INSERT INTO person(name, country) VALUES(:name, :country)');
                    $stmt->bindParam(':name', $name);
                    $stmt->bindParam(':country', $country);

                    if($stmt->execute())
                    {
                        $successMSG = "새로운 사용자를 추가했습니다.";
                    }
                    else
                    {
                        $errMSG = "사용자 추가 에러";
                    }

                } catch(PDOException $e) {
                    die("Database error: " . $e->getMessage());
                }
            }

        }
    ?>

    <html>
      <body>
            <?php
            if (isset($errMSG)) echo $errMSG;
            if (isset($successMSG)) echo $successMSG;
            ?>
           
            <form action="<?php $_PHP_SELF ?>" method="POST">
                Name: <input type = "text" name = "name" />
                Country: <input type = "text" name = "country" />
                <input type = "submit" name = "submit" />
            </form>
     
      </body>
    </html>




    3-1. 윈도우라면 C:\wamp64\www\ 경로에 파일을 생성합니다.



    3-2. 우분투라면 /var/www/html/ 경로에 파일을 생성합니다.



    3-3. 웹브라우저에서  localhost/insert.php 주소로 접속하면 아래와 같은 화면이 보이게 됩니다. 




    정상적으로 테이블에 데이터가 입력되면 출력되는 메시지입니다.




    이름이나 나라를 입력하지 않으면 에러 메시지를 출력하도록 되어 있습니다.






    3-4. 안드로이드 폰의 웹브라우저에서도 테스트해 봅니다.




    접속에 문제가 있다면 다음 포스트 16번부터  참고하세요.



    윈도우 기반 웹 개발 환경 만들기 ( Apache2, PHP, MySQL, PhpMyAdmin )

     http://webnautes.tistory.com/1206 





    3-5. MySQL에서 확인해보면 데이터가 정상적으로 입력된 것을 볼 수 있습니다. 


    SELECT 문으로 testdb 데이터베이스에 있는 Person 테이블의 내용을 조회합니다.

    웹에서 입력한 이름과 주소가 제대로 입력되었는지 확인가능합니다.





    4. Android 앱에서 테스트


    웹서버의 PHP 파일을 통해 데이터베이스에 데이터를 저장하는 안드로이드 앱을 작성합니다.



    4-1. insert.php 파일을 다음 코드로 변경합니다. 


    <?php

        error_reporting(E_ALL);
        ini_set('display_errors',1);

        include('dbcon.php');


        $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");


        if( (($_SERVER['REQUEST_METHOD'] == 'POST') && isset($_POST['submit'])) || $android )
        {

            // 안드로이드 코드의 postParameters 변수에 적어준 이름을 가지고 값을 전달 받습니다.

            $name=$_POST['name'];
            $country=$_POST['country'];

            if(empty($name)){
                $errMSG = "이름을 입력하세요.";
            }
            else if(empty($country)){
                $errMSG = "나라를 입력하세요.";
            }

            if(!isset($errMSG)) // 이름과 나라 모두 입력이 되었다면
            {
                try{
                    // SQL문을 실행하여 데이터를 MySQL 서버의 person 테이블에 저장합니다.
                    $stmt = $con->prepare('INSERT INTO person(name, country) VALUES(:name, :country)');
                    $stmt->bindParam(':name', $name);
                    $stmt->bindParam(':country', $country);

                    if($stmt->execute())
                    {
                        $successMSG = "새로운 사용자를 추가했습니다.";
                    }
                    else
                    {
                        $errMSG = "사용자 추가 에러";
                    }

                } catch(PDOException $e) {
                    die("Database error: " . $e->getMessage());
                }
            }

        }

    ?>


    <?php
        if (isset($errMSG)) echo $errMSG;
        if (isset($successMSG)) echo $successMSG;

    $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");
     
        if( !$android )
        {
    ?>
        <html>
          <body>

                <form action="<?php $_PHP_SELF ?>" method="POST">
                    Name: <input type = "text" name = "name" />
                    Country: <input type = "text" name = "country" />
                    <input type = "submit" name = "submit" />
                </form>
         
          </body>
        </html>

    <?php
        }
    ?>




    4-2. AndroidManifest.xml 매니페스트 파일의  manifest 태그 하위 항목으로 인터넷 접근 허용 퍼미션을 추가합니다.

    android 9.0  이상에서 동작하게 하려면 usesCleartextTraffic 옵션도 추가해야 합니다. 해주지 않으면 “cleartext http traffic to not permitted” 라는 에러가 발생합니다.  



    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.tistory.webnautes.phptest">

        <uses-permission android:name="android.permission.INTERNET" />

        <application
            android:usesCleartextTraffic="true"
            android:allowBackup="true"


     


    4-3. activity_main.xml 레이아웃 파일을 아래 내용으로 바꿉니다. 



    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Name"
            android:id="@+id/textView_main_name" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/editText_main_name" />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Country"
            android:id="@+id/textView_main_country" />

        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/editText_main_country" />

        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Insert"
            android:id="@+id/button_main_insert" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="250dp"
            android:id="@+id/textView_main_result" />

    </LinearLayout>




    4-4. MainActivity.java 자바 파일을 아래 내용으로 바꿉니다.



    다음 줄에 있는 IP 주소를 아파치 웹서버가 설치된  컴퓨터의 IP로 수정하세요.

    private static String IP_ADDRESS = "IP주소";


    안드로이드 에뮬레이터와 서버가 같은 컴퓨터에 동작하는 경우에는 다음 아이피를 입력합니다.

    Android Studio의 에뮬레이터  - 10.0.2.2

    GenyMotion - 192.168.56.1  


    package com.tistory.webnautes.phptest;

    import android.app.ProgressDialog;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import androidx.appcompat.app.AppCompatActivity;
    import android.text.method.ScrollingMovementMethod;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.TextView;

    import java.io.BufferedReader;

    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;

    import java.net.HttpURLConnection;
    import java.net.URL;


    public class MainActivity extends AppCompatActivity {

        private static String IP_ADDRESS = "IP주소";
        private static String TAG = "phptest";

        private EditText mEditTextName;
        private EditText mEditTextCountry;
        private TextView mTextViewResult;


        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            mEditTextName = (EditText)findViewById(R.id.editText_main_name);
            mEditTextCountry = (EditText)findViewById(R.id.editText_main_country);
            mTextViewResult = (TextView)findViewById(R.id.textView_main_result);

            mTextViewResult.setMovementMethod(new ScrollingMovementMethod());


            Button buttonInsert = (Button)findViewById(R.id.button_main_insert);
            buttonInsert.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    String name = mEditTextName.getText().toString();
                    String country = mEditTextCountry.getText().toString();

                    InsertData task = new InsertData();
                    task.execute("http://" + IP_ADDRESS + "/insert.php", name,country);


                    mEditTextName.setText("");
                    mEditTextCountry.setText("");

                }
            });

        }



        class InsertData extends AsyncTask<String, Void, String>{
            ProgressDialog progressDialog;

            @Override
            protected void onPreExecute() {
                super.onPreExecute();

                progressDialog = ProgressDialog.show(MainActivity.this,
                        "Please Wait", null, true, true);
            }


            @Override
            protected void onPostExecute(String result) {
                super.onPostExecute(result);

                progressDialog.dismiss();
                mTextViewResult.setText(result);
                Log.d(TAG, "POST response  - " + result);
            }


            @Override
            protected String doInBackground(String... params) {

                String name = (String)params[1];
                String country = (String)params[2];

                String serverURL = (String)params[0];
                String postParameters = "name=" + name + "&country=" + country;


                try {

                    URL url = new URL(serverURL);
                    HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();


                    httpURLConnection.setReadTimeout(5000);
                    httpURLConnection.setConnectTimeout(5000);
                    httpURLConnection.setRequestMethod("POST");
                    httpURLConnection.connect();


                    OutputStream outputStream = httpURLConnection.getOutputStream();
                    outputStream.write(postParameters.getBytes("UTF-8"));
                    outputStream.flush();
                    outputStream.close();


                    int responseStatusCode = httpURLConnection.getResponseCode();
                    Log.d(TAG, "POST response code - " + responseStatusCode);

                    InputStream inputStream;
                    if(responseStatusCode == HttpURLConnection.HTTP_OK) {
                        inputStream = httpURLConnection.getInputStream();
                    }
                    else{
                        inputStream = httpURLConnection.getErrorStream();
                    }


                    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
                    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

                    StringBuilder sb = new StringBuilder();
                    String line = null;

                    while((line = bufferedReader.readLine()) != null){
                        sb.append(line);
                    }


                    bufferedReader.close();


                    return sb.toString();


                } catch (Exception e) {

                    Log.d(TAG, "InsertData: Error ", e);

                    return new String("Error: " + e.getMessage());
                }

            }
        }


    }




    4-5.  안드로이드 프로젝트를 빌드하여 앱을 테스트할 디바이스 또는 에뮬레이터에 설치합니다.

    앱을 실행시키면 다음과 같은 화면이 보입니다.




    테스트 문자열을 입력하고  INSERT를 터치합니다. 




    성공한 경우 SQL문 처리 성공이라는 메시지가 보이게 됩니다.




    Error: connect timed out 메시지가 보인다면 본 포스트의 3-4를 다시 확인해보세요.

    방어벽 문제 일 수 있습니다. 




    4-6. MySQL에서 확인해보면 정상적으로 입력된 것을 볼 수 있습니다.





    5. 코드 설명

    다음 두 단계를 거쳐서 안드로이드 앱의 데이터가 MySQL 서버에 저장됩니다. 


    1. 안드로이드 앱에서 POST 방식으로 PHP 코드에 데이터를 전달합니다. 

    2. PHP 코드에서 MySQL 서버에 접속하여 전달받은 데이터를 저장합니다.



    우선 안드로이드 앱 코드를 살펴보겠습니다. 


    @Override
    protected String doInBackground(String... params) {

    String name = (String)params[1];
    String country = (String)params[2];


          // 1. PHP 파일을 실행시킬 수 있는 주소와 전송할 데이터를 준비합니다.

          // POST 방식으로 데이터 전달시에는 데이터가 주소에 직접 입력되지 않습니다.
    String serverURL = (String)params[0];



          // HTTP 메시지 본문에 포함되어 전송되기 때문에 따로 데이터를 준비해야 합니다. 

          // 전송할 데이터는 “이름=값” 형식이며 여러 개를 보내야 할 경우에는 항목 사이에 &를 추가합니다.     

          // 여기에 적어준 이름을 나중에 PHP에서 사용하여 값을 얻게 됩니다.

          String postParameters = "name=" + name + "&country=" + country;


    try {
                // 2. HttpURLConnection 클래스를 사용하여 POST 방식으로 데이터를 전송합니다.
    URL url = new URL(serverURL); // 주소가 저장된 변수를 이곳에 입력합니다. 


                HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

    httpURLConnection.setReadTimeout(5000); //5초안에 응답이 오지 않으면 예외가 발생합니다.

    httpURLConnection.setConnectTimeout(5000); //5초안에 연결이 안되면 예외가 발생합니다.

    httpURLConnection.setRequestMethod("POST"); //요청 방식을 POST로 합니다.
    httpURLConnection.connect();


    OutputStream outputStream = httpURLConnection.getOutputStream();
    outputStream.write(postParameters.getBytes("UTF-8")); //전송할 데이터가 저장된 변수를 이곳에 입력합니다. 인코딩을 고려해줘야 합니다.

    outputStream.flush();
    outputStream.close();


                // 3. 응답을 읽습니다.   

    int responseStatusCode = httpURLConnection.getResponseCode();
    Log.d(TAG, "POST response code - " + responseStatusCode);

    InputStream inputStream;
    if(responseStatusCode == HttpURLConnection.HTTP_OK) {

                      // 정상적인 응답 데이터
    inputStream = httpURLConnection.getInputStream();
    }
    else{

                      // 에러 발생 

    inputStream = httpURLConnection.getErrorStream();
    }


                // 4. StringBuilder를 사용하여 수신되는 데이터를 저장합니다.
    InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
    BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

    StringBuilder sb = new StringBuilder();
    String line = null;

    while((line = bufferedReader.readLine()) != null){
    sb.append(line);
    }


    bufferedReader.close();

                

                // 5. 저장된 데이터를 스트링으로 변환하여 리턴합니다.
    return sb.toString();


    } catch (Exception e) {

    Log.d(TAG, "InsertData: Error ", e);

    return new String("Error: " + e.getMessage());
    }

    }




    PHP 코드를 보겠습니다. 

     

            // 1. 안드로이드 코드의 postParameters 변수에 적어준 이름을 가지고 값을 전달 받습니다.
            $name=$_POST['name'];
            $country=$_POST['country'];


        
            // 2. 입력안된 항목이 있을 경우 에러 메시지를 생성합니다.
            if(empty($name)){
                $errMSG = "이름을 입력하세요.";
            }
            else if(empty($country)){
                $errMSG = "나라를 입력하세요.";
            }

            // 3. 에러 메시지가 정의안되어 있다면 이름과 나라 모두 입력된 경우입니다. 

            if(!isset($errMSG))
            {
                try{
                   // 4. SQL문을 실행하여 데이터를 MySQL 서버의 person 테이블에 저장합니다.
                    $stmt = $con->prepare('INSERT INTO person(name, country) VALUES(:name, :country)');
                    $stmt->bindParam(':name', $name);
                    $stmt->bindParam(':country', $country);

                    // 5. SQL 실행 결과를 위한 메시지를 생성합니다.
                    if($stmt->execute())
                    {
                        $successMSG = "새로운 사용자를 추가했습니다.";
                    }
                    else
                    {
                        $errMSG = "사용자 추가 에러";
                    }



    6. 관련 포스팅



    Android PHP MySQL 예제 - 데이터베이스에서 데이터를 JSON 형식으로 가져오기

    http://webnautes.tistory.com/829


    Android PHP MySQL 예제 - 데이터베이스 질의(query) 결과 출력하기

    https://webnautes.tistory.com/1159


    Android PHP MySQL 예제  - 데이터베이스에 데이터 저장 및 JSON 형식으로 가져오는 예제 프로젝트

    http://webnautes.tistory.com/1189  





    7. 참고


    [1]  http://www.simplifiedcoding.net/php-android-tutorial-part-1/ 


    [2]  http://www.simplifiedcoding.net/android-login-and-registration-with-php-mysql/ 


    [3]  http://www.tutorialspoint.com/android/android_php_mysql.htm 



    포스트 작성시에는 문제 없었지만 이후 문제가 생길 수 있습니다.
    댓글로 알려주시면 빠른 시일내에 답변을 드리겠습니다.

    여러분의 응원으로 좋은 컨텐츠가 만들어집니다. 지금 본 내용이 도움이 되었다면 후원 또는 유튜브 구독 부탁드립니다. 감사합니다 : )

    유튜브 구 독 하 기
    후 원 하 기


    TAG

    댓글 465

    • 이전 댓글 더보기
    • kkdm 2019.06.08 19:26


      안녕하세요 컴퓨터 모바일 웹상에서는 데이터베이스가 잘 작동하는데 어플상에서는 inert 누를 경우 아래 php 글자들 <html> <body> <form action> 이런 문구만 뜨고 데이터베이스에 상빕이 되지 않아서 문의드려요 insert는 아래 있는거 사용했습니다.

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.06.08 19:30 신고


        php파일에 다음 부분이 있는 파일인가 보세요.
        html문이 보이지 않게 되어있습니다.


        $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");
          
           if( !$android )

    • 나그네 2019.06.26 01:35


      4. Android 앱에서 테스트 라는 항목에소개된 있는 insert.php 파일과 그 전에 첨부된 insert.php 파일의 내용이 조금 차이가있습니다.
      줄번호로는 대략 9번째줄쯤 아래내용이 나중파일에 추가 및 수정되어있구요

      $android = strpos($_SERVER['HTTP_USER_AGENT'], "Android");
      if( (($_SERVER['REQUEST_METHOD'] == 'POST') && isset($_POST['submit'])) || $android )

      나중 파일을 전체 복붙해서 사용하니 제대로 동작이 되는데 노란텍스트만 기존파일에 추가 사용하니 안드로이드에서 db로 데이터가 저장되지 않습니다.
      참조들 하세요

      좋은 자료 감사합니다.~~

    • 나그네 2019.06.26 16:01


      파이DB에 로컬이 아닌 외부에서 원격으로 php통한 db 데이터저장관련 문의가 있습니다.
      아래와 같은 작업은 진행하였습니다.

      1.파이 설정파일
      sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
      #bind-address = 127.0.0.1 주석처리

      2. 공유기 DDNS 등록 및 포트포워딩 외부 포트 "3306" 내부포트 "22" 설정

      3. 안드로이드 JAVA 파일 IP주소 DDNS 주소 지정
      예) private static String IP_ADDRESS = "goodserver.iptime.org";

      4. mysql root 계정으로 디비에 대한 유저 전체권한설정 예) privileges db파일.* 계정@'%'

      dbcon.php 파일에 $host = 'localhost'; localhost는 지우는게 맞을까요?

      폰에서는 lte로 연결했더니 please wait메세지만 나타나고 있는걸봐서 설정이 틀린것 같긴합니다.
      혹시 놓치고 있는게 있는지 알려주시면 감사하겠습니다.

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.06.26 16:25 신고


        dbcon.php 파일에서 localhost는 그냥 두는게 맞습니다.

        우선 PC에서 웹브라우저로 아파치웹서버에 있는 웹문서에 접근가능한지 보세요..

        그리고 /var/log/apache2/ 위치에 있는 로그파일을 확인하여 접속 시도가 있었는지 확인 해보는게 좋을듯합니다.

        시도한 흔적이 없다면 설정한 DDNS로 접근이 불가능한 상황같습니다.

    • choi 2019.07.17 14:59


      에뮬레이터랑 웹 페이지, 핸드폰에서의 웹페이지 에서 는 db로 저장이 잘되는데 어플을 핸드폰에서
      실행 했을때만 db로저장이 안되네요 ... 뭐때문에 그럴까요?

    • 송송송 2019.07.25 12:53


      에뮬레이터로 실행하고 값을 입력하고 INSERT 버튼을 눌러주면 아래 코드만 에뮬레이터화면에 나타나는데
      어디가 잘못된걸까요?..

      <html> <body> <form action=""method="POST">
      Name: <input type = "text" name = "name" />
      Country: <input type = "text" name = "country" />
      <input type = "submit" name = "submit" />
      </form> </body> </html>


      안드로이드 코드는 IP 주소를 제외하곤 똑같이 작성했습니다.

      public class MainActivity extends AppCompatActivity {

      private static String IP_ADDRESS = "192.168.162.86";
      private static String TAG = "phptest";

      private EditText mEditTextName;
      private EditText mEditTextCountry;
      private TextView mTextViewResult;

      @Override
      protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      mEditTextName = (EditText)findViewById(R.id.editText_main_name);
      mEditTextCountry = (EditText)findViewById(R.id.editText_main_country);
      mTextViewResult = (TextView)findViewById(R.id.textView_main_result);

      mTextViewResult.setMovementMethod(new ScrollingMovementMethod());

      Button buttonInsert = (Button)findViewById(R.id.button_main_insert);
      buttonInsert.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {

      String name = mEditTextName.getText().toString();
      String country = mEditTextCountry.getText().toString();

      InsertData task = new InsertData();
      task.execute("http://" + IP_ADDRESS + "/insert.php", name,country);

      mEditTextName.setText("");
      mEditTextCountry.setText("");
      }
      });

      }

      class InsertData extends AsyncTask<String, Void, String>{
      ProgressDialog progressDialog;

      @Override
      protected void onPreExecute() {
      super.onPreExecute();

      progressDialog = ProgressDialog.show(MainActivity.this,
      "Please Wait", null, true, true);
      }
      @Override
      protected void onPostExecute(String result) {
      super.onPostExecute(result);

      progressDialog.dismiss();
      mTextViewResult.setText(result);
      Log.d(TAG, "POST response - " + result);
      }
      @Override
      protected String doInBackground(String... params) {

      String name = (String)params[1];
      String country = (String)params[2];

      String serverURL = (String)params[0];
      String postParameters = "name=" + name + "&country=" + country;


      try {

      URL url = new URL(serverURL);
      HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();

      httpURLConnection.setReadTimeout(5000);
      httpURLConnection.setConnectTimeout(5000);
      httpURLConnection.setRequestMethod("POST");
      httpURLConnection.connect();

      OutputStream outputStream = httpURLConnection.getOutputStream();
      outputStream.write(postParameters.getBytes("UTF-8"));
      outputStream.flush();
      outputStream.close();

      int responseStatusCode = httpURLConnection.getResponseCode();
      Log.d(TAG, "POST response code - " + responseStatusCode);

      InputStream inputStream;
      if(responseStatusCode == HttpURLConnection.HTTP_OK) {
      inputStream = httpURLConnection.getInputStream();
      }
      else{
      inputStream = httpURLConnection.getErrorStream();
      }

      InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
      BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

      StringBuilder sb = new StringBuilder();
      String line = null;

      while((line = bufferedReader.readLine()) != null){
      sb.append(line);
      }
      bufferedReader.close();

      return sb.toString();

      } catch (Exception e) {

      Log.d(TAG, "InsertData: Error ", e);
      return new String("Error: " + e.getMessage());
      }
      }
      }
      }

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.07.25 17:52 신고


        "4. Android 앱에서 테스트"에 있는 PHP 코드를 사용했는지 확인해보세요..

        안드로이드앱에서는 HTML이 출력안되도록 작성되어 있습니다.

    • 다다다 2019.08.14 14:04


      안녕하세요! 포스팅 잘 봤습니다 ㅎㅎ 혹시 안드로이드 갤러리 사진을 서버에 저장하고 DB에는 서버에 저장된 이미지 경로를 저장하는 예제는 준비하실 예정 없으신가요?

    • 개발개발 2019.09.17 00:09


      안녕하세요. 포스팅 보고 도움이 정말 많이 되었습니다. 감사합니다.
      질문할 게 있는데, 다른 댓글에서도 보이듯이 해당 포스팅과 동일하게 작성했는데
      PC 웹과, 스마트폰 웹에서는 데이터가 잘 들어가는 상황입니다. 하지만 안드로이드 스튜디오로 어플리케이션에서 INSERT를 하면 다른 댓글과 마찬가지로 result 메시지에 php에 있는 html 코드들이 나오게됩니다.
      4-1 소스코드로 변경한 상태이구요..
      대댓글로 답변주신것은 스마트폰에서 웹으로 사용하라 였는데, 막상 스마트폰에서 돌리는 어플리케이션에서는 작동이 안되어서요,,
      피드백 부탁드려도 될까요?

    • 새봄이 2019.09.23 22:22


      1.안드로이드 앱에서 POST 방식으로 PHP 코드에 데이터를 전달합니다.
      2.PHP 코드에서 MySQL 서버에 접속하여 전달받은 데이터를 저장합니다.
      정말 유익하네요 혹시 webnautes님 위에랑 반대로 mysql의 저장된 데이터를 post방식으로 안드로이드앱에서 받아서 화면으로 나타내는 법도 포스팅 해주시면 안될까요?ㅜㅜㅜ

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.09.23 22:28 신고


        데이터베이스에서 가져올땐 보통 아래 포스트처럼 JSON을 사용하는 듯합니다

        https://webnautes.tistory.com/829

        POST 방식을 당장.하긴 힘듭니다..

    • 한글이 2019.10.04 17:59


      앱을 켜서 name country입력하고 insert버튼 누르면 아래에
      Error: Cleartext HTTP traffic to (ip주소) not permitted 라고 뜹니다
      원인이 뭔지 모르겠습니다 ㅠㅠ

      • 한글이 2019.10.04 18:06


        메니페스트파일에
        android:usesCleartextTraffic="true"
        넣어서 오류 뜨지 않게는 해결했는데
        insert버튼 누르면 please wait창 뜨고 사라지고
        새로운 사용자를 추가했습니다. 라는 문구는
        뜨지 않네요ㅠㅠ

      • 한글이 2019.10.04 18:08


        제가 안드로이드랑 서버랑 같은 노트북으로 하고 있는데
        Android Studio의 에뮬레이터 - 10.0.2.2

        GenyMotion - 192.168.56.1
        이렇게 하라는게 어떻게 하라는거죠ㅠㅠ

      • 한글이 2019.10.04 18:24


        아!!!
        제 ip주소 다음에 제가 포트번호를 설정해놔서 포트번호까지 치니까 됐어요!!
        감사합ㄴ디ㅏ ㅠ

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.10.04 20:11 신고


        잘 해결하셨네요^^

    • 질문질문 2019.10.13 17:25


      안녕하세요
      좋은 코드 올려주셔서 감사합니다~
      지금 따라하고 있는데

      java.net.ProtocolException: unexpected end of stream
      에러가 뜹니다ㅠㅠㅠㅠㅠ

      InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "UTF-8");
      BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

      StringBuilder sb = new StringBuilder();
      String line = null;

      while((line = bufferedReader.readLine()) != null){
      sb.append(line);
      }

      에서 while문에서 문제가 생기는 거 같은데 왜그럴까요ㅠㅠㅠ
      php코드는 문제가 없었습니다ㅠㅠㅠ

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.10.13 21:46 신고


        bufferedReader.readLine()는 "\n", "\r" 만날때 까지 한줄을 읽어옵니다.
        해당 문자가 나오지 않았는데 스트림 입력이 완료된게 아닌가 싶습니다.

        읽어온 line 을 출력하면서 어느 부분에서 에러가 나는지 확인해보세요.

    • asjkhf 2019.10.31 15:27


      error:invalid 라는 에러가 뜨는데 뭐가 잘못된걸까요??

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.10.31 15:50 신고


        올려주신 에러 메시지가 너무 간단해서 어떤 상황에서 발생한 건지 알수가 없네요. 좀 더 에러메시지를 찾아봐야 합니다.

    • 개굴이 2019.11.02 16:55


      입력시 Error: Cleartext HTTP traffic to (ip주소) not permitted 오류가 뜨는데 뭐가 문젠지 모르겟어요ㅠㅠ
      제 ip주소도 적용해보고 Android Studio의 에뮬레이터 - 10.0.2.2 이 주소로도 적용해봤는데 여전히 오류가 뜹니다.
      위에분은 자기 포트번호 추가해서 해결되셧다는데 제 ip주소에 뭔가 더 추가해야하는건가요..?

    • 개굴이 2019.11.03 18:52


      cleartext 추가하니 이번엔 이런 오류가 뜹니다. 이건 어떻게 처리해야하나요..? ㅠㅠㅠ Error: socket failed: EPERM (Operation not permitted)

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.11.04 09:24 신고


        메니패스트 파일에 다음 퍼미션을 추가해보세요.

        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.INTERNET"/>

    • kkk1112 2019.11.08 19:49


      안드로이드 애뮬은 윈도우에서 돌리고
      우분투는 가상으로 돌리고있습니다.
      그런데 Error:failed to connect to/제IP(port443) from/애뮬IP(port48260) after 5000ms라 뜹니다ㅠㅠ


      앗 죄송합니다.. 리눅스 리부팅하니까 되네ㅐ요 ㅠㅠ

    • 첼쉬 2019.11.13 22:18


      아마존 ec2 nginx mariadb php 쓰고 있습니다.
      연결시 Error:failed to connect to/IP(port443) from/애뮬IP(port37420) after 5000ms이라 뜨네요.... 계속 안됩니다 ㅠㅠ

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.11.14 09:27 신고


        에뮬레이터서 접근 가능한 아이피인가 확인해보세요.

        애물레이터의 웹브라우저에서 서버에서 만든 웹문서에 접근해보면 됩니다.

    • 첼쉬 2019.11.14 13:35


      애뮬의 브라우저로 접속하면 이름을 입력하세요등 문장이 뜹니다 php파일에서 임의로 name에 값을 넣어주고 브라우저로 실행시키면 값은 추가가 되네요. 하지만 앱에서는 위에 오류는 그대로 납니다..... 주소로 접속을 못하는 것일가요.
      ---------------------------------------

      nginx mariadb 모두 재시작 하니까 되네요...ㄷㄷ 예제 감사드립니다.

    • 423 2019.12.01 23:05


      'MYSQL_ATTR_INIT_COMMAND' 이 부분이 에러가 나는데 왜그럴까요? ㅠㅠ..

    • 반가워요 2019.12.02 00:43


      package com.tistory.webnautes.phptest; 이부분 에러납니다 어떻게해결하나요?

      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.12.02 08:21 신고


        패키지 이름은 생성한 프로젝트의 패키지 이름이어야 합니다.

        코드 복사시 package를 빼고 복사하세요

        package는 프로젝트 생성시 추가되는 거로 사용해야합니다.

    • 김세진 2019.12.06 05:00


      GRANT ALL PRIVILEGES ON testdb.* to 'webnautes'@'localhost' IDENTIFIED BY 0314; 이런식으로 입력하면

      ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'IDENTIFIED BY 0314' at line 1 위와같이 에러가 뜹니다. 방법이있을까요

    • 김세진 2019.12.07 23:48


      Failed to connect to the database: SQLSTATE[HY000] [1045] Access denied for user 'sejin'@'localhost' (using password: YES) 현재 이렇게 연결이되지않고 있습니다. 비밀번호 , IP , db이름 모두 정확한데 안되는 이유를 도저히 모르겠습니다. ㅜㅜ
      참고로 localhost를 127.0.0.1 로도 해봤습니다 ㅜㅜ
      ㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡㅡ
      혹시나해서 비밀번호도 다시 명령어를 사용해 바꾸어보았습니다.

      비밀번호를 영대문자 영소문자 특수문자를 이용하여 구성도 해보았습니다 ㅜ


      • Favicon of https://webnautes.tistory.com BlogIcon webnautes 2019.12.08 17:40 신고


        검색해보니 패스워드가 틀려서 발생하는 오류라는 군요.

        dbcon.php 파일에서 계정 정보를 입력시 아래처럼 작은 따옴표로 감쌌는지 확인해보세요.


        <?php

        $host = 'localhost';
        $username = 'webnautes'; # MySQL 계정 아이디
        $password = 'apple9!'; # MySQL 계정 패스워드
        $dbname = 'testdb'; # DATABASE 이름

Designed by Tistory.