버그 해결을 위한 모든 질문을 던져
0 votes
856 views

상황_​
유니티와 php를 이용한 게임 제작 중​

유니티와 php 사이에서 post로 값을 주고 받으며 게임이 차례차례 진행 됨​

유니티와 php 사이에서 값은 json방식으로 주고 받음​

(실시간 진행되는 게임 방식이 아니며 클릭시 특정 모션을 보여주는 방식. 웹페이지 로드와 유사함)​

유니티에서 php로 보낸 값을 php에서 처리하는 과정에서 생기는 이슈에 관하여 질문​

 

질문 1. 유니티에서 보낸 값을 php단에서 받고 특정 페이지의 로직 통과 후 다른 페이지로 이동시켜야 한다면 (즉 하나의 페이지에서 로직 처리 후 값을 바로 리턴하지 않고 다른 페이지로 가야하는 경우 ex.로그인이나 쇼핑몰 로직등??) form을 이용하여 처리된 값을 다음 페이지로 보내는 방식으로 하면 되는지?​

즉 php 내에서 페이지 이동시 form을 이용하여 값을 이동시키면 되는지? 아니면 포워딩 방식? 으로 해야하는지​

포워딩 방식이라면 어떤 코드로 해야 하는지 궁금합니다. ​

 

 

질문 2. 세션 값을 클라이언트(유니티)에서 가져가기 위해 최종 PHP페이지에 노출하는 것이 맞나요?
(최종 값을 출력하는 PHP페이지에 세션 관련 값도 노출하는 방식이 맞는지)

질문 3. 보안 관련 질문 : 이렇게 POST로 값을 주고 받으며 PHP에서는 값을 출력하고 유니티에서 해당 값을 가져가는 것이 맞는지

게임 선배님께 미리 감사드립니다.

asked (2 point) , 856 views

1 답변

+1 vote

공통. PHP 세션이 유지되는 방법은, HTTP 프로토콜 상의 쿠키 헤더를 활용합니다.
이 쿠키가 유지되지 않으면 세션도 유지되지 못합니다. 

따라서 권장되는 방법은 카카오 API나 네이버 API 처럼 토큰 발급/인증 메커니즘(OAuth2.0 같은)을 구성하고, 해당 토큰을 클라이언트측에 유지 시키는 방법을 활용해야 합니다.

쿠키가 생성되는 메커니즘은.

1. 서버측에 최초 요청 -> session_start() 함수 호출
   --> 여기서 응답 헤더에 "Set-Cookie: PHPSESSID=.....; ...."가 추가됩니다.

2. 그 이후 요청엔 HTTP 클라이언트(즉, 브라우저)가 모든 요청에 "Cookie: PHPSESSID=...."을 셋팅해서 송신하게 됩니다.

이런 식인데, 보통 HTTP 프로토콜 관련 라이브러리들은 내부적으로 해당 쿠키들을 처리 하지 않아요.
그래서, 토큰을 발급하고, JSON이나 XML로 클라측에 송신해줘야 합니다. 그리고 왠만하면 REST 개념에 맞춰서 각 메서드의 기능을 정확하게 구현하는게 좋습니다.

1. 서버측에 최초 요청,

POST /auth/token HTTP/1.1
Host: rest.example.com
User-Agent: My-Client; v=0.3
Content-Type: application/json
Content-Length: ....
.....

{ "app-key": "..........." }

HTTP/1.1 200 OK
....
Content-Type: application/json
Content-Length: ....
....

{ "user-token": "USER_TOKEN", "refresh-token": "....." }

2. 이후 요청

POST /path/to/service HTTP/1.1
Host: rest.example.com
....
Authorization: bearer USER_TOKEN  <-- 이 헤더가 Cookie를 대신하는 역할.
Content-Type: application/json
Content-Length: ....
....

 

질문 1. 유니티에서 PHP쪽으로 요청을 보낸다는건 아마도 HTTP 관련 플러그인(예를들어 언리얼의 VaRest 같은)을 활용하시겠죠, 그런 경우에서 페이지 리다이렉션 (301, 302) 응답은 적절치 못한 선택이 될 수 있습니다. (물론 해당 플러그인이 cURL같은 라이브러리를 캡슐화 한 경우 301, 302는 문제가 되지 않겟지요.

form은 정확히 말하자면, HTML DOM 컴포넌트중 하나입니다. 프로토콜의 일부가 아니에요. 페이지 전환은 사용하실 수 없습니다. 사용할 수 있다고 해도 지옥도가 펼쳐질 거라고 봅니다.

PHP Autoloader를 구현하시고, 개별 기능들을 클래스로 구현하신 뒤에, 해당 클래스들을 호출하는 형태로 작성하시는 편이 정신건강(?)에 이롭습니다.

<?php

// -- .autoloader.php 샘플

function __autoload($className) {
   $className = str_replace('\\', '/', $className);
   if (file_exists($fullPath = __DIR__ . "/classes/$className.class.php"))
      require_once($fullPath);
}

// -- .entry.php 샘플

include_once( __DIR__ . '/.autoloader.php');

function __run() {
   $RequestUri = $_SERVER['REQUEST_URI'];
   $path = (($pathSeperator = strpos($RequestUri, '?')) !== false ?
      substr($RequestUri, 0, $pathSeperator) : $RequestUri;

   $path = trim($path, '/');
   $method = strtolower($_SERVER['REQUEST_METHOD']);
   if (file_exists($fullPath = __DIR__ . '/' . $path . '.' . $method . '.php')) {
      $arguments = $method == 'get' ? $_GET : ($method == 'post' ? $_POST : null);

      if (isset($_SERVER["CONTENT_TYPE"])) {
         $type = strtolower($_SERVER["CONTENT_TYPE"]);
         if (($PS = strpos($type, ';')) !== false) {
             $type = trim(substr($type, 0, $PS));
         }
                            }
         if (($method != 'get' && $method != 'delete') &&
             $type == 'application/json')
         { $arguments = json_decode(file_get_contents('php://input'), true); }
      }

      include ($fullPath);
   }
}

// -- classes/Resp.class.php
<?php

class Resp {
   static function normalize() {
      header('Content-Type: application/json');
   }
   .......
}

// -- auth/test.php 샘플

<?php

Resp::normalize();
// ... DO SOMETHING HERE
// include로 참조된 경우엔 참조한 위치에 존재하는 지역 변수에 접근이 가능: $arguments에
// 요청 인자가 들어감
echo json_encode([ ... ], JSON_UNESCAPED_UNICODE);

// -- .htaccess
# ------------------------------------------------------------
# Disable MultiViews and Indexes.
# ------------------------------------------------------------

Options -MultiViews
RewriteEngine On

DirectorySlash Off
Options -Indexes


# ------------------------------------------------------------
# Forward all access to /.entry.php except real-existed files.
# ------------------------------------------------------------

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.+)$ .entry.php [QSA,L]
DirectoryIndex .entry.php


# ------------------------------------------------------------
# Deny all access to ~.php except index.php.
# ------------------------------------------------------------

<FilesMatch "\.php$"> 
     Order allow,deny 
     Deny from all
</FilesMatch>

<FilesMatch "\.class.php$"> 
     Order allow,deny 
     Deny from all
</FilesMatch>

<FilesMatch "\.conf$"> 
     Order allow,deny 
     Deny from all
</FilesMatch>

<FilesMatch "^\."> 
     Order allow,deny 
     Deny from all
</FilesMatch>

<FilesMatch "\.(post|get|put|delete|patch)\.php"> 
     Order allow,deny 
     Deny from all
</FilesMatch>

<FilesMatch "^\."> 
     Order allow,deny 
     Deny from all
</FilesMatch>

<FilesMatch "^\.main.php$"> 
     Order allow,deny 
     Allow from all
</FilesMatch>

질문 2. 토큰을 발급받아 그걸 토큰 키로 사용하면 세션 값(php-session id)을 노출시킬 필요가 없습니다. 

게임 플레이 자체에 필요한 값들이 있다면 그것들은 당연히 JSON으로 encode할 때 포함 시켜줘야되겠죠.

 

질문 3. 보안 관련에서 대응방법은 2가지가 있습니다.

1. SSL 인증서 설치, https 사용. 

URL을 제외하고 아무것도 수정하지 않아도 됩니다. 플러그인 측에서는 수정해줘야 할지도 모르겠지만요.

2. 비용이나 하드웨어 지원 측면에서 SSL 도입이 어렵다 하면, 수동으로 암호화 시켜서 Content-Type을 application/my-enc 이런 형태로 비표준으로 지정하시고, 해당되는 경우엔 위에 표기된 php://input 스트림으로 입력을 받아 복호화 시켜서 처리하게끔 구성해도 됩니다만, 퍼포먼스는 살짝 떨어질 수 있습니다.

물론 이 경우에도, 암호화 모듈을 php 모듈로 달아서 사용하면 퍼포먼스가 크게 감쇠하지는 않을 겁니다.

애초에 퍼포먼스가 목적이라면, php를 사용하는 것 보다,
자바로 웹소켓 서버를 작성하시던지 그것도 모자라다 하면 C++로 가야겠죠.

PHP가 퍼포먼스가 아주 심하게 떨어지는 것은 않지만, 바이트코드로 컴파일된 자바에 비하면 조금 느리긴 합니다.
(체감될 정도로 아주 심하게 차이가 나진 않더군요)

answered (12 point)

버그 해결을 위해 도움을 구하고, 도움을 주세요. 우리는 그렇게 발전합니다.

throw bug 는 프로그래밍에 대한 전분야를 다룹니다. 질문,논의거리,팁,정보공유 모든 것이 가능합니다. 프로그래밍과 관련이 없는 내용은 환영받지 못합니다.

255 질문
388 answers
396 댓글
509 users