MSSQL 서버에 사용자 PASSWORD 데이터가 'SHA2_xxx'방식으로 암호화되어 저장되있습니다.

 

그럼 php로 입력받은 id와 password값을 처리하기 위해서 아래와 같은 쿼리를 날려 준 후 결과값이 있으면 로그인 허용을 해주면 될 것입니다.

select * from 사용자정보
where 유저id = $id
and 비밀번호 = $password

하지만 위처럼  $password 값이 암호화 처리되지 않은 값이라면 쿼리를 아래처럼 수정해야합니다.

select * from 사용자정보
where 유저id = $id
and 비밀번호 =  HASHBYTES('SHA2_256' , $password)

하지만 sql 수준의 hashbytes 함수의 return값은 binary형(0x.....)식 입니다.

만약 사용자정보 테이블의 유저id 컬럼이 binary형식으로 저장이 안 되어있는 경우라면 아래처럼 character 형태로 convert를 해줄 수도 있습니다.

select * from 사용자정보
where 유저id = $id
and 비밀번호 =  CONVERT(NVARCHAR(32),HASHBYTES('SHA2_256' , $password))

아니면 php 수준에서 아래와 같이 hash()함수로 처리한 뒤에 쿼리로 넘겨주는 방법도 활용할 수 있습니다.

$password_hash = hash("sha256", $password)

 

 앞서 예를 든 상황처럼 게시글이 등록했을 때 teams로 알림을 받고 싶은 내용 중에 '제목, 글쓴이, 내용, 날짜'등이 있을 수 있습니다.

 이런 내용들을 파라미터로 url에 실어서 호출해주면 그 내용도 teams로 받을 수 있습니다.

http://localhost/send_message.php?param0=0번&param1=1번&param2=2번&param3=3번

 위와 같이 (pram0 ~ param3, 4개의 파라미터)url을 호출하여 실제로 teams에 메시지가 어떻게 전송되는지 확인해보겠습니다. 


 1. 코드 작성

 php 서버에 'send_message.php'라는 파일을 생성하여 아래처럼 코드를 작성해줍니다.

param0 부터 param10까지 11개로 요청받은 파라미터를 처리하는 예제입니다.

<?php
error_reporting(E_ALL);
ini_set("display_errors", 1);

if(extension_loaded("curl")){
	echo "cUrl extension is loaded";
}else{
 echo "cUrl extension is not available";
}

function WebhookSendMessage($text){
    $url = '생성한 WEBHOOK 주소';
    $ch = curl_init();
    
    $test =[
        "@type" => "MessageCard",
        "@context" => "http://schema.org/extensions",
        "summary" => $text["param5"]." ".$text["param4"]." ".$text["param3"]." ".$text["param2"],
        "themeColor" => "0076D7",
        "title" => "메시지 제목",
        "sections" => [
            [
                "activityTitle" => "",
                "activitySubtitle" => "",
                "activityImage" => "",
                "facts" => [
                    [
                        "name" => "Parameter 0",
                        "value" => $text["param0"]
                    ],
                    [
                        "name" => "Parameter 1",
                        "value" => $text["param1"]
                    ],
                    [
                        "name" => "Parameter 2",
                        "value" => $text["param2"]
                    ],                    
                    [
                        "name" => "Parameter 3",
                        "value" => $text["param3"]
                    ]    
                ],
                "text" => "테스트 메시지 입니다."
            ]
        ]
    ];

    $jsonDataEncoded = json_encode($test, true);  
    
    $header = array();
    $header[] = 'Content-type: application/json';

    curl_setopt($ch, CURLOPT_URL,$url);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 );
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $jsonDataEncoded);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_HTTPHEADER, $header);

    echo "<br><br> 전송결과 <Br>";
    $result = curl_exec($ch);
    curl_close($ch);
    echo "결과값 ";
    var_dump($result);
}

$messageArray = array(
    "param0" => trim($_GET['param0']),
    "param1" => trim($_GET['param1']),
    "param2" => trim($_GET['param2']),
    "param3" => trim($_GET['param3']),
    "param4" => trim($_GET['param4']),
    "param5" => trim($_GET['param5']), 
    "param6" => trim($_GET['param6']),
    "param7" => trim($_GET['param7']),
    "param8" => trim($_GET['param8']), 
    "param9" => trim($_GET['param9']), 
    "param10" => trim($_GET['param10']), 
);

echo "입력받은 파라미터 출력 <Br>";
print_r($messageArray);

WebhookSendMessage($messageArray);
?>

2. Get 방식으로 url에 파라미터를 전달하여 메시지가 전달되는지 확인해봅니다.

http://localhost/send_message.php?param0=0번&param1=1번&param2=2번&param3=3번

3. URL 호출 결과확인

 여기서 warning 경고는 무시하셔도 됩니다.

 위에 코드에서처럼 모든 에러를 출력하게 작성하였기 때문에 선언이 안 된 param4~ param10까지의 파라미터에 값이 없어서 발생한 경고입니다.

결과확인

 결과 화면을 살펴보시면 아래 부분에 http/2 200 부분에 정상적으로 호출된 것을 확인할 수 있습니다.


4. Teams 메시지 확인

 그럼 실제로 teams에 메시지가 잘 도착했을까요

팀즈에도 잘 도착한 것을 확인할 수 있습니다.


 php curl, json 처리 등의 방식을 활용하여 teams webhook을 활용하여 notification을 간단하게 구현해봤습니다.

 

 MS Teams 메신저의 Notification 기능을 간단하게 구현해봤습니다.

 예를 들어 웹 사이트에 게시글이 등록(수정) 될 때 마다 알림을 받고 싶은 경우를 들어 설명하겠습니다.

대략적인 시스템 구성은 아래와 같습니다.

API 순서

 먼저 teams에 알림을 받기 위해선 webhook을 생성해 줘야하며 순서는 아래를 참고해주세요

*참고 : Webhook(웹훅)이란?
https://simsimjae.medium.com/%EC%9B%B9%ED%9B%85%EC%9D%B4%EB%9E%80-e41cf1ba92f0
(참고 : https://g.co/kgs/Zv5x7p)

1. 팀즈 '팀 만들기'

팀 - 팀 만들기


2. 팀 - 채널 만들기

채널 만들기


3. 채널 - 커넥터 생성

 


4. 커넥터 - Incoming Webhook 구성하기


5. webhook 생성


5. Webhook 복사

 아래 생성된 Webhook URL을 복사해둡니다.

만약 URL을 다시 확인하려면?

왼쪽에 '구성됨' 메뉴를 선택후 구성한 Webhook을 클릭 후 '관리'를 누르시면 확인할 수 있습니다.


 

 

 

 

  회사의 API서버가 무려 ASP CLASSIC으로 되어 있었습니다.

같은 서버에 다행히 PHP도 설치가 되어있어서, 서버 구성에 손대지 않고 API를 이 참에 다 갈아엎고자 PHP로 작업을 진행하고 있습니다.

 보통 mysql(maria db)과 많이 사용하여서 Mssql과 연동하는 작업은 전무했던터라 자주사용하는 소스를 공유드리고자 합니다.


1. DB 접속정보를 갖고 있는 config.php

 config.php를 생성하여 상수로 자주 사용할 정보들을 define 해줍니다.

<?php
	// IP는 예시이므로 사용하실 IP로 변경해주세요
    // DB 주소 (메인 DB와 테스트 DB를 사용)
    define('DB_MAIN','192.100.100.111');
    define('DB_TEST','192.100.100.112');

	// 데이터베이스 이름
    define('DB_EMPL','사원관리DB');
    define('DB_SALARY','급여관리DB');

	// DB 접속 정보
    define('DB_ID_ADMIN','id_admin');
    define('DB_PW_ADMIN','pw_admin');

	// 인코딩 
    define('DB_CHARACTERSET','UTF-8');

?>

2. config.php를 include 해주고 같은 경로에 select.php 라는 예제 파일을 아래와 같이 작성해보겠습니다.

각 코드별로 주석을 기재하였으나 어려우신 분들은 언제든 댓글 달아주세요 :)

<?php
    header('Content-Type: text/html; charset=utf-8');

    // 테스트할 때 모든 에러를 출력해주는게 좋습니다.
    error_reporting( E_ALL ); 
    ini_set( "display_errors", 1 );

    // DB 연결과 관련한 상수에 대한 값을 불러와줍니다.
    // 예를들어 select.php, update.php 등의 CRUD 작업페이지가 여러개라 할 때, DB의 접속 정보가 변경된 상황이 발생할 경우 
    // Config.php만 변경해주면 됩니다. 
    include 'config.php';
?>

<html>
    <head>
    <meta charset="utf-8">
    </head>

    <body>
        <?php
        // 연결할 MSSQL 서버에 대한 정보를 입력해줍니다.
        $serverName = DB_TEST;
        $connectionOptions = array(
            "database" => DB_EMPL,        // 데이터베이스명
            "uid" => DB_ID_ADMIN,             // 유저 아이디
            "pwd" => DB_PW_ADMIN,             // 유저 비번
            "CharacterSet" => DB_CHARACTERSET // 한글꺠짐 방지!
        );

        
        // --------------------------------------------------------------------
        // SQL 조건문에 변수를 넣을 경우 활용 하는 방법 
        // 1) 변수에 그대로 값 대입
        $F_EMPL_CODE = '사번';
        $F_START_DATE = '날짜';

        // 2) URL에 입력된 변수를 불러올 경우
        // 테스트는 GET / API 호출은 POST 사용
        // ex) http://localhost/select.php?EMPL_CODE=사번&START_DATE=데이타
        $F_EMPL_CODE = $_GET['F_EMPL_CODE'];
        $F_START_DATE = $_GET['F_START_DATE'];
        // --------------------------------------------------------------------

        // 결과값을 받을 변수
        $F_START_TIME = '';

        // DB 연결
        $dbconn = sqlsrv_connect($serverName, $connectionOptions); 
        // 연결 확인
        if ($dbconn) {
            echo "DB 연결 완료<br><hr>";
        }else{
            echo "DB 연결 실패<Br>";
            die( print_r( sqlsrv_errors(), true));
            echo "<hr>";
        }

        // 쿼리 작성
        $query = "SELECT * FROM 출근기록테이블
                WHERE 사번 = '$F_EMPL_CODE' and 날짜 = '$F_START_DATE'"; 

        // 쿼리를 실행하여 statement 를 얻어온다
        $params = array();
        $options = array( "Scrollable" => SQLSRV_CURSOR_KEYSET );
        $stmt = sqlsrv_query($dbconn, $query, $params, $options );

        // 쿼리 결과 'row' 수를 반환해준다
        $row_count = sqlsrv_num_rows($stmt);
        
        // 결과가 1개 이상 있다면?
        if($row_count >= 1){
            // statement 를 돌면서 필드값을 가져온다
            while ($row = sqlsrv_fetch_array($stmt, SQLSRV_FETCH_ASSOC))
            {   
                //  출력할 $row['컬럼명']; 형태로 출력해줌
                $F_START_TIME = (string) $row['근무시간'];
                echo $F_START_TIME."<Br>";
            }   
        }else{
            echo "조회된 정보가 없습니다";
        } 
        
        // 데이터 출력후 statement 를 해제한다
        sqlsrv_free_stmt($stmt);    

        // 데이터베이스 접속을 해제한다
        sqlsrv_close($dbconn);
        ?>
    </body>
</html>

 

개발환경

  • OS - Windows 10
  • IDE - Visual Studio Code (이하 VS Code)
  • Framework Version - Codeigniter 3 (이하 Ci3)
  • Bitnami WAMP 로컬 서버 경로 - 드라이브\Bitnami\apache2\htdocs

 이 전에 Ci3로 생성한 task라는 웹 서버 경로(Bitnami\apache2\htdocs)에 static 폴더를 생성 한 후,

템플릿 적용에 필요한 폴더(css, js 등)을 복사하는 작업까지 마쳤습니다.

 이번엔 템플릿을 적용하기 위해 <link>, <script> 태그 내에 경로를 설정하여 Ci3에서 경로지정을 어떻게 효과적으로 하는 지에 대해 중점적으로 알아보겠습니다


1. 컨트롤러 생성

 Ci 3는 MVC 패턴이 기반이므로 컨트롤러부터 생성을 해줘야합니다.

'Task/Application/Controller' 경로 안에 'Home.php'라는 파일을 생성한 후 'Home' 컨트롤러 클래스를 작성해줍니다.

<?php
defined('BASEPATH') or exit('No direct script access allowed');

class Home extends CI_Controller
{
    
  public function __construct()
  {
    parent::__construct();
  }

  public function index()
  {
    // 
  }

}

 'Task' 컨트롤러를 아래 경로로 호출해보겠습니다.

http://localhost(:포트를 별도로 설정한 경우 포트)/task/index.php/home

빈 화면이 정상적으로 출력됩니다


2. View 호출

 Ci3는 컨트롤러를 호출하면 컨트롤러 내에서 화면 구성 코드가 작성된 'View'를 호출하는 구조를 갖습니다.

기본으로 생성된 'welcome_message.php'를 호출해보겠습니다.

 아래 'Controllers/Welcome.php' 코드를 먼저 살펴보면 index() 함수안에 view를 불러오는 코드가 작성되있습니다.

defined('BASEPATH') OR exit('No direct script access allowed');

class Welcome extends CI_Controller {

	/**
	 * Index Page for this controller.
	 *
	 * Maps to the following URL
	 * 		http://example.com/index.php/welcome
	 *	- or -
	 * 		http://example.com/index.php/welcome/index
	 *	- or -
	 * Since this controller is set as the default controller in
	 * config/routes.php, it's displayed at http://example.com/
	 *
	 * So any other public methods not prefixed with an underscore will
	 * map to /index.php/welcome/<method_name>
	 * @see https://codeigniter.com/user_guide/general/urls.html
	 */
	public function index()
	{
    	// welcome_message view 호출
		$this->load->view('welcome_message');
	}
}

'Task/application/views'경로 안에 'welcome_message.php' 파일이 있습니다.

<?php
defined('BASEPATH') OR exit('No direct script access allowed');
?><!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="utf-8">
	<title>Welcome to CodeIgniter</title>

	<style type="text/css">

	::selection { background-color: #E13300; color: white; }
	::-moz-selection { background-color: #E13300; color: white; }

	body {
		background-color: #fff;
		margin: 40px;
		font: 13px/20px normal Helvetica, Arial, sans-serif;
		color: #4F5155;
	}

	a {
		color: #003399;
		background-color: transparent;
		font-weight: normal;
	}

	h1 {
		color: #444;
		background-color: transparent;
		border-bottom: 1px solid #D0D0D0;
		font-size: 19px;
		font-weight: normal;
		margin: 0 0 14px 0;
		padding: 14px 15px 10px 15px;
	}

	code {
		font-family: Consolas, Monaco, Courier New, Courier, monospace;
		font-size: 12px;
		background-color: #f9f9f9;
		border: 1px solid #D0D0D0;
		color: #002166;
		display: block;
		margin: 14px 0 14px 0;
		padding: 12px 10px 12px 10px;
	}

	#body {
		margin: 0 15px 0 15px;
	}

	p.footer {
		text-align: right;
		font-size: 11px;
		border-top: 1px solid #D0D0D0;
		line-height: 32px;
		padding: 0 10px 0 10px;
		margin: 20px 0 0 0;
	}

	#container {
		margin: 10px;
		border: 1px solid #D0D0D0;
		box-shadow: 0 0 8px #D0D0D0;
	}
	</style>
</head>
<body>

<div id="container">
	<h1>Welcome to CodeIgniter!</h1>

	<div id="body">
		<p>The page you are looking at is being generated dynamically by CodeIgniter.</p>

		<p>If you would like to edit this page you'll find it located at:</p>
		<code>application/views/welcome_message.php</code>

		<p>The corresponding controller for this page is found at:</p>
		<code>application/controllers/Welcome.php</code>

		<p>If you are exploring CodeIgniter for the very first time, you should start by reading the <a href="user_guide/">User Guide</a>.</p>
	</div>

	<p class="footer">Page rendered in <strong>{elapsed_time}</strong> seconds. <?php echo  (ENVIRONMENT === 'development') ?  'CodeIgniter Version <strong>' . CI_VERSION . '</strong>' : '' ?></p>
</div>

</body>
</html>

  코드를 보시면 대부분 HTML로 구성되있음을 알 수 있는데 처음 MVC를 접하였을 때 이 부분에서 많이 헷갈려하십니다.

 View 코드만 불러오면 되는 걸 왜 Controller를 통해서 불러와야 하냐는 의문을 갖는 것이 당연합니다.

 간단하게 설명드리면 화면구성(UI)과 데이터처리(데이터 모델링)을 분리하여야 유지보수도 쉽고 컨트롤러만 사용자의 요청을 처리하면되는 구조가 보안성을 더 높여주기 때문입니다.
 데이터처리, 화면 등의 모든 코드가 한 페이지에만 작성 될 경우 웹 브라우저 내에 데이터가 노출될 위험이 굉장히 높아집니다

* MVC 패턴에 대한 내용은 자세히 다음에 다루도록하겠습니다.

 다시 돌아와서 'Home' 컨트롤러 클래스 index()함수에 'Welcome' 컨트롤러 클래스의 index()함수 내에 작성된 아래의 코드를 복사하여 붙여줍니다.

$this->load->view('welcome_message');

 그럼 'Controllers/Home.php' 클래스는 아래와 같이 완성됩니다.

class Home extends CI_Controller
{
    
  public function __construct()
  {
    parent::__construct();
  }

  public function index()
  {
    // 테스트를 위해 Welcome_message 뷰를 호출 해보자
    $this->load->view('welcome_message');
  }

}

작성 후 다시 아래 주소를 호출해볼까요

http://localhost(:포트를 별도로 설정한 경우 포트)/task/index.php/home

&amp;nbsp;welcome_message 뷰가 잘 불러와졌습니다

 'Welcome' 컨트롤러 클래스처럼 welcome_message 뷰가 잘 호출되었습니다.


 Ci3의 컨틀롤러-뷰의 관계에 대해 간단하게 작성해봤습니다.

글이 길어질까봐 템플릿을 실제로 적용하는건 다음 편으로 미루겠습니다 ;)

먼저 프레임워크 설치방법은 아래 글을 참고해주세요

Codeigniter 설치 : https://motown.tistory.com/2

개발환경

  • OS - Windows 10
  • IDE - Visual Studio Code (이하 VS Code)
  • Framework Version - Codeigniter 3 (이하 Ci3)
  • Bitnami WAMP 로컬 서버 경로 - 드라이브\Bitnami\apache2\htdocs

준비

1. codeigniter에 아래 링크에서 다운로드 받은 부트스트랩 무료 템플릿을 적용해보겠습니다.

https://startbootstrap.com/theme/sb-admin-2

 

SB Admin 2 - Free Bootstrap Admin Theme - Start Bootstrap

Like our free products? Our pro products are even better! Go Pro Today!

startbootstrap.com

2. WAMP 로컬서버 경로에 다운받은 Ci3 폴더를 복사해주고 이름을 폴더 이름을 'task'로 변경해줍니다.

task 폴더 구성

3. 작업을 위해 Visual Studio Code에서 위 폴더를 열어줍니다.

4. 서버 접속 확인

http://localhost(:포트)/task/

task 경로에 Ci 3가 잘 설치되었습니다.&amp;nbsp;


템플릿 적용하기

 템플릿 적용을 하기 위해 다운받은 템플릿의 'css, js' 소스와 이미지 같은 리소스를 불러와줘야 합니다.

 

1. 템플릿 가져오기

먼저 'task'경로 안에 템플릿을 저장할 'static'이라는 폴더를 생성해줍니다.

Static 폴더 생성

2. 복사할 템플릿 파일 확인

 다운로드 받은 템플릿 파일 압축을 푼 후에 index.html 을 확인해보겠습니다.

sb admin 2 템플릿 폴더

index.html을 크롬에서 열면 템플릿 사이트를 확인 할 수 있습니다.

지금은 소스파일을 봐야하므로 우클릭 하여 '연결 프로그램'을 메모장이나, VS code 등의 에디터로 열어봅니다.

<!DOCTYPE html>
<html lang="en">

<head>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>SB Admin 2 - Dashboard</title>

    <!-- Custom fonts for this template-->
    <link href="vendor/fontawesome-free/css/all.min.css" rel="stylesheet" type="text/css">
    <link
        href="https://fonts.googleapis.com/css?family=Nunito:200,200i,300,300i,400,400i,600,600i,700,700i,800,800i,900,900i"
        rel="stylesheet">

    <!-- Custom styles for this template-->
    <link href="css/sb-admin-2.min.css" rel="stylesheet">

</head>

 index.html의 <head>태그 부분을 살펴보겠습니다.

<link>태그 에 '*.css' 파일들을 불러온 것을 확인 할 수 있습니다.

    <!-- Bootstrap core JavaScript-->
    <script src="vendor/jquery/jquery.min.js"></script>
    <script src="vendor/bootstrap/js/bootstrap.bundle.min.js"></script>

    <!-- Core plugin JavaScript-->
    <script src="vendor/jquery-easing/jquery.easing.min.js"></script>

    <!-- Custom scripts for all pages-->
    <script src="js/sb-admin-2.min.js"></script>

    <!-- Page level plugins -->
    <script src="vendor/chart.js/Chart.min.js"></script>

    <!-- Page level custom scripts -->
    <script src="js/demo/chart-area-demo.js"></script>
    <script src="js/demo/chart-pie-demo.js"></script>

</body>

</html>

 그리고 <body>태그 맨 밑 부분에 '*.js' 파일들을 불러 왔습니다.


index.html 파일처럼 템플릿을 불러오기위해 css, js 등의 파일들을 불러와줘야합니다.

이미지같은 리소스가 있는 템플릿이라면 이 역시 마찬가지구요.

 

3.  템플릿 파일을 Ci 3의 Static 폴더에 복사

템플릿 적용을 위해 필요한 소스, 리소스 복사

템플릿 적용에 필요한 폴더들을 위에서 생성한 staic 폴더에 복사해줍니다.

task 서버의 static 폴더에 복사


템플릿 적용을 위한 준비가 되었습니다.

다음에 템플릿을 ci 3에 적용해보겠습니다.

php 출력 구문은 대표적으로 echo, print, print_r, var_dump 이 네 가지를 가장 많이 사용합니다.

 각각의 차이가 어떤 점이 있는지, 문자열/숫자/1차원 배열/2차원 배열의 변수를 각각 선언한 뒤 출력을 해보며 확인해보겠습니다.

 왜 제목에 출력 '구문(함수)'로 써놨는지 그 이유도 알아보겠습니다.

 

<?php

// 문자열 type
$test_string = "Hello World";
// 숫자(정수) type
$test_int = 1234;
// 1차원 배열
$test_array = array("0", "HYUNDAI", "iOniq 5");
// 2차원 배열
$test_array2D = array( // 1차원 배열을 3개 갖는 2차원 배열 선언과 동시에 초기화
    array("1", "PEUGEOT", 5008),
    array("2", "CITROEN", "C5"),
    array("3", "DS", "DS3 Crossback")
);

echo "1) echo로 변수 출력<br>";
echo $test_string;
echo "<Br>";
echo $test_int;
echo "<Br>";
echo $test_array;
echo "<Br>";
echo $test_array2D;
echo "<Br>";
echo "<hr>";

echo "2) print로 변수출력 <br>";
print $test_string;
echo "<Br>";
print $test_int;
echo "<Br>";
print $test_array;
echo "<Br>";
print $test_array2D;
echo "<Br>";
echo "<hr>";

echo "3) print_r로 변수출력 <br>";
print_r($test_string);
echo "<Br>";
print_r($test_int);
echo "<Br>";
print_r($test_array);
echo "<Br>";
print_r($test_array2D);
echo "<Br>";
echo "<hr>";

echo "4) print_r로 변수출력 <br>";
var_dump($test_string);
echo "<Br>";
var_dump($test_int);
echo "<Br>";
var_dump($test_array);
echo "<Br>";
var_dump($test_array2D);
echo "<Br>";
?>

바로 출력 결과를 확인해볼까요

결과만 보면 'echo'와 'print' 키워드는 같은 결과를 나타내지만 큰 차이가 있습니다.


1. echo vs print

 간혹 php의 print는 함수고 echo는 함수가 아니다라는 글을 보았는데 정확히는 둘 다 '아니지만 print는 반은 함수다' 라고 생각합니다.

 일반적으로 함수라하면 값을 언제나 반환하지 않더라도 여차하면 '반환할 수 있어'라는 기능을 내포하고 있으니까요.

print는 동작시 언제나 '1'을 반환하고 있습니다.

echo print("");
print print("");
print_r(print(""));
var_dump(print(""));

 위에 처럼 print에 빈 문자를 각각의 출력문으로 출력하면 값이 어떻게 될까요.

var_dump()는 아무 출력값이 안 나오고 나머지는 '1'을 출력하게 됩니다.

 결론적으로 print는 함수는 아니지만 언제나 '1'을 출력하는 성질을 갖고 있으며, 개인적으로 잘 사용하진 않지만 '삼항연산'을 출력 할 때 외에는 print를 쓸 이유가 굳이 있을까 하는 생각이듭니다.

(삼항연산 참고 : https://pjw48.net/wordpress/2017/02/08/helloworld-php/)


* echo나 print는 왜 배열을 출력하지 못 할까요

이 둘의 공통점은 아래와 같습니다.

Non-string values will be coerced to strings, even when the strict_types directive is enabled.

문자열이 아니면 강제로 문자열로 바꿀껀데, 못 바꾸게 생겼으면 데이터 타입을 출력하겠다 정도로 이해하시면 되지 않을까 싶습니다.


2. print_r vs var_dump

 이 둘의 가장 대표적인 차이는 '누가 더 자세히 안내해주냐' 입니다.

다시 결과를 확인해볼까요

3) print_r로 변수출력
Hello World
1234
Array ( [0] => 0 [1] => HYUNDAI [2] => iOniq 5 )
Array ( [0] => Array ( [0] => 1 [1] => PEUGEOT [2] => 5008 ) [1] => Array ( [0] => 2 [1] => CITROEN [2] => C5 ) [2] => Array ( [0] => 3 [1] => DS [2] => DS3 Crossback ) )

4) print_r로 변수출력
D:\Bitnami\apache2\htdocs\playground\php_study\print_function.php:50:string 'Hello World' (length=11)

D:\Bitnami\apache2\htdocs\playground\php_study\print_function.php:52:int 1234

D:\Bitnami\apache2\htdocs\playground\php_study\print_function.php:54:
array (size=3)
  0 => string '0' (length=1)
  1 => string 'HYUNDAI' (length=7)
  2 => string 'iOniq 5' (length=7)

D:\Bitnami\apache2\htdocs\playground\php_study\print_function.php:56:
array (size=3)
  0 => 
    array (size=3)
      0 => string '1' (length=1)
      1 => string 'PEUGEOT' (length=7)
      2 => int 5008
  1 => 
    array (size=3)
      0 => string '2' (length=1)
      1 => string 'CITROEN' (length=7)
      2 => string 'C5' (length=2)
  2 => 
    array (size=3)
      0 => string '3' (length=1)
      1 => string 'DS' (length=2)
      2 => string 'DS3 Crossback' (length=13)

 위에 결과를 보면 var_dump로 출력한 결과가 더 자세하다는 걸 볼 수 있습니다.

데이터 타입부터, 출력된 경로의 위치까지 자세히 출력해주기 때문에 디버깅시 유용하게 사용할 수 있습니다.

 그렇기 때문에 'null'을 var_dump() 출력할 수 있으나 print_r()은 출력할 수 없게 됩니다.

 

또, print_r은 문자열을 반환 하지만 var_dump는 아무 값을 반환하지 않습니다.

아래 print_r과 var_dump의 함수를 비교해보면 한 눈에 알 수 있습니다.

print_r(mixed $value, bool $return = false): string|bool
var_dump(mixed $value, mixed ...$values): void

 

결론적으로 print_r은 단어 그대로 'print'에 기능이 집중되어있습니다.


* 참고

php 공식 문서에 echo와 print문에 대한 설명이 있으니 참고해주세요

https://www.php.net/manual/en/function.echo

https://www.php.net/manual/en/function.print.php

 

PHP: print - Manual

mvpetrovich of 2007 could just use single quotes as his string delimiters (see the example in the current documentation).It's not ALWAYS appropriate, but generally it is best (the Zend Framework coding standards have a good take on this). It yields a numbe

www.php.net

https://www.php.net/manual/en/function.print-r

 

PHP: print_r - Manual

Here's a PHP version of print_r which can be tailored to your needs. Shows protected and private properties of objects and detects recursion (for objects only!). Usage:void u_print_r ( mixed $expression [, array $ignore] )Use the $ignore parameter to provi

www.php.net

https://www.php.net/manual/en/function.var-dump

개발환경

  • Windows10 OS
  • Bitnami-WAMP 사용

WAMP 환경에서 Codeigniter 3(이하 Ci3) 설치하는 방법이며, 굉장히 간단합니다

결론적으로 Ci3을 다운 받은 후 'htdocs ' 폴더 안에 압축만 풀어주면 됩니다.

 

* 참고로 WAMP에서 htdocs 폴더의 역할은 서버 내에 웹 사이트(PHP Application)가 저장되는 곳을 의미하게 됩니다.

예를 들어 WAMP로 구성된 환경의 웹 서버에서 test123'과 'test456'이라는 사이트가 서비스 중이라 할 때 'htdocs/test123', 'htdocs/test456'의 경로에서 각각의 웹 사이트가 서비스 중이라고 이해하시면 됩니다.

참고 : https://nonipc.com/entry/htdocs%EB%9E%80-php-%ED%8C%8C%EC%9D%BC-%EC%97%B4%EA%B8%B0-%EB%B0%8F-php-%EC%84%A4%EC%A0%95

 


1. 아래 Codeigniter 사이트 접속

https://codeigniter.com/download

 

Welcome to CodeIgniter

Strong Security We take security seriously, with built-in protection against CSRF and XSS attacks. Version 4 adds context-sensitive escaping and CSP

codeigniter.com


2. Ci3 다운로드

버전은 3.x을 사용 할겁니다.

 

Ci 사이트 화면


3. 압축해제

WAMP 환경에서 'apache2/hdocs' 경로 안에 압축을 풀어준 후 폴더이름이 복잡하므로 변경해줍니다.

저는 'ci3'로 변경한 후 진행할겁니다.

WAMP에 Ci3 설치 경로 (저 같은 경우는 bitnami 설치 후 폴더명을 'bitnami'로 변경하여 사용합니다


4. 설치 확인

3에서 'ci3'로 폴더명을 변경하였으므로 아래 주소로 접속 시 첨부한 화면처럼 접속이 되면 정상적으로 설치가 완료된 걸 확인할 수 있습니다. 

 

http://localhost/ci3/

Ci3 설치 확인


WAMP 환경이 구축되어 있다면 Ci3 설치는 굉장히 간단합니다.

개발환경

  • Windows OS
  • Bitnami WAMP 사용
  • 실습경로 : Bitnami 설치폴더/htdocs/ci3 

Codeigniter 3(이하 Ci 3) Framework를 사용하다보면 거슬리는 문제가 하나 있습니다.

 바로 생성한 페이지 사이에 'index.php'라는 경로를 계속 명시해줘야하는 것인데 우선 ci 3의 컨트롤러 부분부터 간단히 살펴본 후에 Ci 3에서 사용자의 요청(웹 사이트 요청)을 어떤 순서로 처리하는지 정리해보겠습니다.


1. Ci 3 의 컨트롤러 살펴보기

Ci 3를 설치하면 아래 경로에 MVC기반의 디렉토리가 생성되어있고 php 클래스 파일이 있습니다.

\bitnami\apache2\htdocs\ci3\application\controllers

위 경로 안에 'welcome.php'라는 파일을 확인 할 수 있는데, 간단히 살펴보면 "Welcome"이라는 php 클래스 파일입니다.

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Welcome extends CI_Controller {

	/**
	 * Index Page for this controller.
	 *
	 * Maps to the following URL
	 * 		http://example.com/index.php/welcome
	 *	- or -
	 * 		http://example.com/index.php/welcome/index
	 *	- or -
	 * Since this controller is set as the default controller in
	 * config/routes.php, it's displayed at http://example.com/
	 *
	 * So any other public methods not prefixed with an underscore will
	 * map to /index.php/welcome/<method_name>
	 * @see https://codeigniter.com/user_guide/general/urls.html
	 */
	public function index()
	{
		$this->load->view('welcome_message');
	}
}

2. MVC 패턴?

Ci 3는 MVC 패턴 구조를 갖고 있습니다. (참고 : https://developer.mozilla.org/ko/docs/Glossary/MVC)

 그래서 작성한 페이지를 호출하기 위해선 'C (Controller)'를 호출해줘야만 합니다.

MVC로 이루어진 프레임워크에선 C에 해당하는 컨트롤러가 나머지 V(View-보여주는 방식)와 M (Model-데이터 정의)를 말 그대로 '컨트롤'하기 때문입니다.


3. "Welcome" 클래스는 어떻게 호출이 될까

'http://localhost/ci3/'로 접속해보면 아래화면 처럼 Welcome 클래스가 호출됩니다.

 근데 주소에 'Welcome'이라는 단어도 없는데 어떻게 호출이 된 것인지 확인해보겠습니다.

bitnami\apache2\htdocs\ci3\application\config\routes.php

위 경로의 'routes.php' 소스를 살펴 보면 'defaut_controller'라는 Key에 'welcome'이 명시되있는 걸 확인 할 수 있습니다.

Ci 3에선 Directory를 감추기 위해 이런식으로 호출할 주소와 클래스를 맵핑 시킬 수 있습니다.

$route['default_controller'] = 'welcome';
$route['404_override'] = '';
$route['translate_uri_dashes'] = FALSE;

defaut_controller의 key 역할은 아무 Class를 주소에 명시하지 않았을 경우에 Defalut로 호출할 클래스를 설정하는 부분입니다.

그렇기 때문에 'http://localhost/ci3/' 주소를 호출하면 'Welcome' 컨트롤러 클래스가 호출되는 겁니다.


그럼 아래처럼 한 번 설정을 추가해볼까요.

$route['default_controller'] = 'welcome';
$route['GO'] = 'welcome'; // GO라는 key를 추가
$route['404_override'] = '';
$route['translate_uri_dashes'] = FALSE;

2번 째 줄에 'GO'라는 key를 추가하면서 welcome 클래스와 맵핑을 시켰습니다.

'http://localhost/ci3/go'를 호출하면 welcome 클래스를 실행시키겠지만...

결과는 호출되지 않습니다.

Ci 3의 특성상 주소(경로)에 'index.php'를 컨트롤러 앞에 작성해주지 않으면 호출이 안 되기 때문입니다.

(왜 꼭 index.php가 들어가야 작동하는 지에 대해선 다음에 다뤄보겠습니다.)

주소/ci3/index.php/클래스명(routes의 key명)으로 하니 호출이 된다!

http://localhost/ci3/GO
http://localhost/ci3/index.php/GO

주소를 아래 처럼 index.php를 넣어주니 정상적으로 작동이됩니다.

마찬가지로 'http://localhost/ci3/index.php/welcome'로 호출하여도 'http://localhost/ci3/'와 같이 welcome 컨트롤러 클래스가 호출됩니다.

 

+ Recent posts