분류 php

PHP에 대해 가장 많이 묻는 11 가지 질문

컨텐츠 정보

  • 조회 375 (작성일 )

본문

PHP (Hypertext Pre-processor)는 웹 사이트 및 웹 애플리케이션 개발에 주로 사용되는 인기 있는 서버 측 스크립팅 언어입니다. 

정적 또는 동적 웹 사이트를 구축하는 데 사용할 수 있습니다. 매우 간단하고 배우기 쉽습니다. 그래서 오늘 우리는 PHP에 대해 가장 자주 묻는 11 가지 질문을 확인할 것입니다.


https://dev.to/truemark/11-most-asked-questions-about-php-4p1f


PHP에 대해 가장 많이 묻는 11 가지 질문 


1. PHP에서 SQL 삽입을 방지하는 방법은 무엇입니까? 


대답: 


준비된 문과 매개 변수가 있는 쿼리를 사용합니다.


매개 변수와는 별도로 데이터베이스 서버로 전송되고 구문 분석되는 SQL 문입니다. 이렇게 하면 공격자가 악성 SQL을 주입 할 수 없습니다.


기본적으로 이를 달성하기 위한 두 가지 옵션이 있습니다.


i. PDO 사용 (지원되는 모든 데이터베이스 드라이버 용) :


$stmt = $pdo->prepare('SELECT * FROM employees WHERE name = :name');

$stmt->execute([ 'name' => $name ]);

foreach ($stmt as $row) {
    // Do something with $row
}


ii. MySQLi 사용 (MySQL 용) :


$stmt = $dbConnection->prepare('SELECT * FROM employees WHERE name = ?');
$stmt->bind_param('s', $name); // 's' specifies the variable type => 'string'

$stmt->execute();

$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
    // Do something with $row
}


MySQL 이외의 데이터베이스에 연결하는 경우 참조 할 수 있는 드라이버 별 두 번째 옵션이 있습니다 (예 : PostgreSQL의 경우 pg_prepare () 및 pg_execute ()). PDO는 보편적 인 옵션입니다.


연결을 올바르게 설정 


PDO를 사용하여 MySQL 데이터베이스에 액세스 할 때 실제 준비된 명령문은 기본적으로 사용되지 않습니다. 이 문제를 해결하려면 준비된 명령문의 에뮬레이션을 비활성화 해야 합니다. PDO를 사용하여 연결을 만드는 예는 다음과 같습니다.


$dbConnection = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'password');

$dbConnection->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);


위의 예에서 오류 모드는 꼭 필요한 것은 아니지만 추가하는 것이 좋습니다. 이렇게 하면 스크립트가 문제가 발생할 때 치명적인 오류로 중지되지 않습니다. 그리고 개발자에게 PDOException으로 발생하는 오류를 포착 할 수 있는 기회를 제공합니다.


그러나 필수는 첫 번째 setAttribute() 행으로, PDO에 에뮬레이트 된 준비된 명령문을 비활성화하고 실제 준비된 명령문을 사용하도록 지시합니다. 이렇게 하면 문과 값이 MySQL 서버로 전송되기 전에 PHP가 구문 분석하지 않도록 합니다 (공격자가 악의적 인 SQL을 주입 할 기회가 없음).


생성자의 옵션에서 문자 집합을 설정할 수 있지만 '이전'버전의 PHP (5.3.6 이전)는 DSN의 문자 집합 매개 변수를 자동으로 무시한다는 점에 유의해야 합니다.


설명 


준비하기 위해 전달한 SQL 문은 데이터베이스 서버에 의해 구문 분석되고 컴파일 됩니다. 매개 변수 (? 또는 위의 예에서 : name과 같은 명명 된 매개 변수)를 지정하여 필터링 할 위치를 데이터베이스 엔진에 알립니다. 그런 다음 execute를 호출하면 준비된 문이 지정한 매개 변수 값과 결합됩니다.


여기서 중요한 것은 매개 변수 값이 SQL 문자열이 아니라 컴파일 된 명령문과 결합된다는 것입니다. SQL 주입은 데이터베이스에 보낼 SQL을 생성 할 때 스크립트가 악성 문자열을 포함하도록 속이는 방식으로 작동합니다. 따라서 매개 변수와는 별도로 실제 SQL을 전송하여 의도하지 않은 결과가 나올 위험을 제한합니다.


준비된 명령문을 사용할 때 보내는 모든 매개 변수는 문자열로 처리됩니다 (데이터베이스 엔진이 일부 최적화를 수행 할 수 있으므로 매개 변수도 물론 숫자로 끝날 수 있음). 위의 예에서 $ name 변수에 'Sarah'가 포함 된 경우; DELETE FROM employees 결과는 단순히 " 'Sarah'; DELETE FROM employee"문자열을 검색하는 것이며 빈 테이블로 끝나지 않을 것입니다.


준비된 명령문을 사용하는 또 다른 이점은 동일한 세션에서 동일한 명령문을 여러 번 실행하면 한 번만 구문 분석되고 컴파일 되어 속도가 향상된다는 것입니다. 아, 그리고 삽입에 대해 수행하는 방법에 대한 예는 다음과 같습니다 (PDO 사용).


$preparedStatement = $db->prepare('INSERT INTO table (column) VALUES (:column)');

$preparedStatement->execute([ 'column' => $unsafeValue ]);


준비된 문을 동적 쿼리에 사용할 수 있습니까? 


쿼리 매개 변수에 대해 준비된 명령문을 계속 사용할 수 있지만 동적 쿼리 자체의 구조는 매개 변수화 할 수 없으며 특정 쿼리 기능은 매개 변수화 할 수 없습니다.


이러한 특정 시나리오의 경우 가장 좋은 방법은 가능한 값을 제한하는 화이트리스트 필터를 사용하는 것입니다.


// Value whitelist
// $dir can only be 'DESC', otherwise it will be 'ASC'
if (empty($dir) || $dir !== 'DESC') {
   $dir = 'ASC';
}


2. 문자열에 특정 단어가 포함되어 있는지 확인하는 방법은 무엇입니까? 


대답: 


다른 문자열 내부에서 한 문자열의 발생을 찾는 데 사용되는 strpos() 함수를 사용할 수 있습니다.


$a = 'How are you?';

if (strpos($a, 'are') !== false) {
    echo 'true';
}


! == false의 사용은 의도적 인 것입니다 (! = false도 === true도 원하는 결과를 반환하지 않습니다). strpos()는 건초 더미 문자열에서 needle 문자열이 시작되는 오프셋을 반환하거나 needle이 발견되지 않으면 부울 false를 반환합니다. 0은 유효한 오프셋이고 0은 "거짓"이므로! strpos ($ a, 'are')와 같은 더 간단한 구조를 사용할 수 없습니다.


대체 답변 : 


정규 표현식을 사용할 수 있습니다. strpos에 비해 단어 일치에 더 낫습니다. fare, care, stare 등과 같은 문자열에 대해서도 true를 반환하므로 이는 단어 경계를 사용하여 정규 표현식에서 간단히 피할 수 있습니다. 에 대한 간단한 일치는 다음과 같습니다.


$a = 'How are you?';

if (preg_match('/\bare\b/', $a)) {
    echo 'true';
}


성능 측면에서 strpos는 약 3 배 더 빠르며 한 번에 100 만 건의 비교를 수행 할 때 preg_match를 완료하는 데 1.5 초가 걸렸고 strpos의 경우 0.5 초가 걸렸습니다.


단어 단위 뿐만 아니라 문자열의 일부를 검색하려면 다음과 같은 정규 표현식을 사용하는 것이 좋습니다.


$a = 'How are you?';
$search = 'are y';
if(preg_match("/{$search}/i", $a)) {
    echo 'true';
}


정규식 끝에 있는 i는 정규식을 대소 문자를 구분하지 않도록 변경합니다. 원하지 않는 경우 생략 할 수 있습니다.


이제 $search 문자열이 어떤 식으로든 삭제되지 않았기 때문에 어떤 경우에는 상당히 문제가 될 수 있습니다. 즉, $search가 사용자 입력 인 것처럼 체크인을 통과하지 못할 수도 있습니다. 다른 정규식처럼 작동합니다.


또한 다양한 정규 표현식 Regex101에 대한 설명을 테스트하고 볼 수 있는 훌륭한 도구가 있습니다.


두 기능 세트를 단일 다목적 기능 (선택 가능한 대소 문자 구분 포함)으로 결합하려면 다음과 같이 사용할 수 있습니다.


function FindString($needle,$haystack,$i,$word)
{   // $i should be "" or "i" for case insensitive
    if (strtoupper($word)=="W")
    {   // if $word is "W" then word search instead of string in string search.
        if (preg_match("/\b{$needle}\b/{$i}", $haystack)) 
        {
            return true;
        }
    }
    else
    {
        if(preg_match("/{$needle}/{$i}", $haystack)) 
        {
            return true;
        }
    }
    return false;
    // Put quotes around true and false above to return them as strings instead of as bools/ints.
}


3. PHP에서 mysql_* 함수를 사용하지 않는 이유는 무엇입니까? 


대답: 


MySQL 확장 :

  • 활발한 개발 중이 아닙니다.
  • 공식적으로 PHP 5.5 (2013 년 6 월 출시)부터 사용되지 않습니다.
  • PHP 7.0 (2015 년 12 월 릴리스)에서 완전히 제거되었습니다.
    이는 2018 년 12 월 31 일 현재 지원되는 PHP 버전에 존재하지 않음을 의미합니다. 지원하는 PHP 버전을 사용하는 경우 보안 문제가 해결되지 않는 버전을 사용하고 있는 것입니다.
  • OO 인터페이스 부족
  • 지원하지 않음 :
    -, 비 차단, 비동기 쿼리
    -, 준비된 문 또는 매개 변수가 있는 쿼리
    -, 저장 프로 시저
    -, 여러 문
    -, Transactions
    -, "새로운"암호 인증 방법 (MySQL 5.6에서 기본적으로 설정 됨, 5.7에서 필요)
    -, MySQL 5.1 이상의 새로운 기능

더 이상 사용되지 않기 때문에 코드를 사용하면 향후 코드가 덜 보장됩니다. 준비된 명령문에 대한 지원 부족은 별도의 함수 호출을 사용하여 수동으로 이스케이프 하는 것보다 외부 데이터를 이스케이프 하고 인용하는 더 명확하고 오류가 발생하기 쉬운 방법을 제공하므로 특히 중요합니다.


SQL 확장 비교를 참조하십시오.


4. PHP의 배열에서 요소를 삭제하는 방법은 무엇입니까? 


대답: 


배열 요소를 삭제하는 방법에는 여러 가지가 있으며, 일부는 다른 작업보다 특정 작업에 더 유용합니다.


하나의 배열 요소 삭제 


하나의 배열 요소 만 삭제하려면 unset() 또는 \ array_splice()를 사용할 수 있습니다. 또한 값이 있고 요소를 삭제할 키를 모르는 경우 \ array_search()를 사용하여 키를 가져올 수 있습니다.


i. unset() 


unset()을 사용하면 배열 키가 변경 / 재 인덱싱 되지 않습니다. 키를 다시 색인화 하려면 unset() 뒤에 \ array_values​​()를 사용하면 모든 키가 0부터 시작하는 숫자 열거 키로 변환됩니다.


Code 


<?php

    $array = [0 => "a", 1 => "b", 2 => "c"];
    unset($array[1]);
                //↑ Key which you want to delete

?>


Output


[
    [0] => a
    [2] => c
]


ii. \array_splice() method 


\ array_splice()를 사용하면 키가 자동으로 다시 색인화 되지만 모든 키를 숫자 키로 변환하는 \ array_values​​()와 달리 연관 키는 변경되지 않습니다. 또한 \ array_splice()에는 키가 아닌 오프셋이 필요합니다! 두 번째 매개 변수로.


Code 

<?php

    $array = [0 => "a", 1 => "b", 2 => "c"];
    \array_splice($array, 1, 1);
                        //↑ Offset which you want to delete

?>


Output 

[
    [0] => a
    [1] => c
]


unset()과 동일한 array_splice()는 배열을 참조로 가져 오므로 해당 함수의 반환 값을 배열에 다시 할당하지 않으려는 것입니다.


여러 배열 요소 삭제 


여러 배열 요소를 삭제하고 unset() 또는 \array_splice()를 여러 번 호출하지 않으려면 값 또는 키를 알고 있는지에 따라 \ array_diff() 또는 \ array_diff_key() 함수를 사용할 수 있습니다. 삭제할 요소입니다.


i. \array_diff() method 


삭제할 배열 요소의 값을 알고 있다면 \array_diff()를 사용할 수 있습니다. unset() 이전과 마찬가지로 배열의 키를 변경 / 재 인덱싱 하지 않습니다.


Code 


<?php

    $array = [0 => "a", 1 => "b", 2 => "c"];
    $array = \array_diff($array, ["a", "c"]);
                               //└────────┘→ Array values which you want to delete

?>


Output 


[
    [1] => b
]


ii. \array_diff_key() method 


삭제할 요소의 키를 알고 있다면 \array_diff_key()를 사용하고 싶습니다. 여기에서 키를 값이 아닌 두 번째 매개 변수의 키로 전달해야 합니다. 그렇지 않으면 \array_flip()으로 배열을 뒤집어 야합니다. 또한 여기서 키는 변경 / 재 색인되지 않습니다.


Code 


<?php

    $array = [0 => "a", 1 => "b", 2 => "c"];
    $array = \array_diff_key($array, [0 => "xy", "2" => "xy"]);
                                    //↑           ↑ Array keys which you want to delete
?>


Output 


[
    [1] => b
]



또한 unset() 또는 \array_splice()를 사용하여 동일한 값을 가진 여러 요소를 삭제하려면 \array_keys()를 사용하여 특정 값에 대한 모든 키를 가져온 다음 모든 요소를 ​​삭제할 수 있습니다.


5. PHP 및 cURL을 사용하여 YouTube API에서 관련 썸네일을 가져올 수 있는 방법이 있습니까? 


대답: 


각 YouTube 동영상에는 4 개의 생성 된 이미지가 있습니다. 예측 가능한 형식은 다음과 같습니다.


https://img.youtube.com/vi/<insert-youtube-video-id-here>/0.jpg
https://img.youtube.com/vi/<insert-youtube-video-id-here>/1.jpg
https://img.youtube.com/vi/<insert-youtube-video-id-here>/2.jpg
https://img.youtube.com/vi/<insert-youtube-video-id-here>/3.jpg


목록의 첫 번째 이미지는 전체 크기 이미지이고 다른 이미지는 축소판 이미지입니다. 기본 미리보기 이미지 (예 : 1.jpg, 2.jpg, 3.jpg 중 하나)는 다음과 같습니다.


https://img.youtube.com/vi/<insert-youtube-video-id-here>/default.jpg


고품질 버전의 미리보기 이미지를 보려면 다음과 유사한 URL을 사용하세요.


https://img.youtube.com/vi/<insert-youtube-video-id-here>/hqdefault.jpg


HQ와 유사한 URL을 사용하는 중간 품질 버전의 미리보기 이미지도 있습니다.


https://img.youtube.com/vi/<insert-youtube-video-id-here>/mqdefault.jpg


미리보기 이미지의 표준 정의 버전의 경우 다음과 유사한 URL을 사용하세요.


https://img.youtube.com/vi/<insert-youtube-video-id-here>/sddefault.jpg


축소판의 최대 해상도 버전을 보려면 다음과 유사한 URL을 사용하십시오.


https://img.youtube.com/vi/<insert-youtube-video-id-here>/maxresdefault.jpg


위의 모든 URL은 HTTP에서도 사용할 수 있습니다. 또한 약간 더 짧은 호스트 이름 i3.ytimg.com이 위의 예제 URL에서 img.youtube.com 대신 작동합니다.


또는 YouTube Data API (v3)를 사용하여 미리보기 이미지를 가져올 수 있습니다.


대체 답변 : 


YouTube Data API를 사용하여 동영상 미리보기 이미지, 캡션, 설명, 등급, 통계 등을 검색 할 수 있습니다. API 버전 3에는 키 *가 필요합니다. 키를 얻고 동영상 만들기 : 목록 요청 :


https://www.googleapis.com/youtube/v3/videos?key=YOUR_API_KEY&part=snippet&id=VIDEO_ID


예제 PHP 코드 


$data = file_get_contents("https://www.googleapis.com/youtube/v3/videos?key=YOUR_API_KEY&part=snippet&id=T0Jqdjbed40");
$json = json_decode($data);
var_dump($json->items[0]->snippet->thumbnails);


Output 


object(stdClass)#5 (5) {
  ["default"]=>
  object(stdClass)#6 (3) {
    ["url"]=>
    string(46) "https://i.ytimg.com/vi/T0Jqdjbed40/default.jpg"
    ["width"]=>
    int(120)
    ["height"]=>
    int(90)
  }
  ["medium"]=>
  object(stdClass)#7 (3) {
    ["url"]=>
    string(48) "https://i.ytimg.com/vi/T0Jqdjbed40/mqdefault.jpg"
    ["width"]=>
    int(320)
    ["height"]=>
    int(180)
  }
  ["high"]=>
  object(stdClass)#8 (3) {
    ["url"]=>
    string(48) "https://i.ytimg.com/vi/T0Jqdjbed40/hqdefault.jpg"
    ["width"]=>
    int(480)
    ["height"]=>
    int(360)
  }
  ["standard"]=>
  object(stdClass)#9 (3) {
    ["url"]=>
    string(48) "https://i.ytimg.com/vi/T0Jqdjbed40/sddefault.jpg"
    ["width"]=>
    int(640)
    ["height"]=>
    int(480)
  }
  ["maxres"]=>
  object(stdClass)#10 (3) {
    ["url"]=>
    string(52) "https://i.ytimg.com/vi/T0Jqdjbed40/maxresdefault.jpg"
    ["width"]=>
    int(1280)
    ["height"]=>
    int(720)
  }
}


키가 필요할 뿐만 아니라 계획 한 API 요청 수에 따라 결제 정보를 요청 받을 수 있습니다. 그러나 하루에 몇 백만 건의 요청이 무료입니다.


https://salman-w.blogspot.com/2010/01/retrieve-youtube-video-title.html


6. $this보다 self를 언제 사용해야 합니까? 


대답: 


$this를 사용하여 현재 개체를 참조하십시오. self를 사용하여 현재 클래스를 참조하십시오. 

즉, 비 정적 멤버에는 $this-> member를 사용하고 정적 멤버에는 self :: $member를 사용하십시오.


다음은 비 정적 및 정적 멤버 변수에 대해 $this 및 self를 올바르게 사용하는 예입니다.


<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo $this->non_static_member . ' '
           . self::$static_member;
    }
}

new X();
?>


다음은 비 정적 및 정적 멤버 변수에 대해 $this 및 self의 잘못된 사용 예입니다.


<?php
class X {
    private $non_static_member = 1;
    private static $static_member = 2;

    function __construct() {
        echo self::$non_static_member . ' '
           . $this->static_member;
    }
}

new X();
?>


다음은 멤버 함수에 대해 $this를 사용한 다형성의 예입니다.


<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        $this->foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>



다음은 멤버 함수에 self를 사용하여 다형성 동작을 억제하는 예입니다.


<?php
class X {
    function foo() {
        echo 'X::foo()';
    }

    function bar() {
        self::foo();
    }
}

class Y extends X {
    function foo() {
        echo 'Y::foo()';
    }
}

$x = new Y();
$x->bar();
?>


아이디어는 $this-> foo()가 현재 객체의 정확한 유형이 무엇이든 foo() 멤버 함수를 호출한다는 것입니다. 객체가 X 유형이면 X :: foo()를 호출합니다. 객체가 Y 유형이면 Y :: foo()를 호출합니다. 그러나 self :: foo()를 사용하면 X :: foo()가 항상 호출됩니다.


http://www.phpbuilder.com/board/showthread.php?t=10354489에서 : http://board.phpbuilder.com/member.php?145249-laserlight 작성


대체 답변 : 


키워드 self는 적어도 정적 멤버로 제한하는 방식으로 '현재 클래스'를 참조하지 않습니다. 비 정적 멤버의 컨텍스트 내에서 self는 현재 객체에 대해 vtable (vtable의 wiki 참조)을 우회하는 방법도 제공합니다. parent :: methodName()을 사용하여 함수의 부모 버전을 호출 할 수 있는 것처럼 self :: methodName()을 호출하여 메서드의 현재 클래스 구현을 호출 할 수 있습니다.


class Person {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }

    public function getTitle() {
        return $this->getName()." the person";
    }

    public function sayHello() {
        echo "Hello, I'm ".$this->getTitle()."<br/>";
    }

    public function sayGoodbye() {
        echo "Goodbye from ".self::getTitle()."<br/>";
    }
}

class Geek extends Person {
    public function __construct($name) {
        parent::__construct($name);
    }

    public function getTitle() {
        return $this->getName()." the geek";
    }
}

$geekObj = new Geek("Ludwig");
$geekObj->sayHello();
$geekObj->sayGoodbye();


그러면 다음이 출력됩니다.


안녕하세요 저는 Ludwig the Geek Goodbye입니다. 


sayHello()는 $ this 포인터를 사용하므로 vtable이 호출되어 Geek :: getTitle()을 호출합니다. sayGoodbye()는 self :: getTitle()을 사용하므로 vtable이 사용되지 않고 Person :: getTitle()이 호출됩니다. 두 경우 모두 인스턴스화 된 객체의 메서드를 다루고 있으며 호출 된 함수 내에서 $ this 포인터에 액세스 할 수 있습니다.


7. 표시 할 PHP 오류를 얻는 방법은 무엇입니까? 


대답: 


다음과 같이 할 수 있습니다.


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


그러나 이로 인해 PHP가 구문 분석 오류를 표시하지는 않습니다. 이러한 오류를 표시하는 유일한 방법은 다음 줄을 사용하여 php.ini를 수정하는 것입니다.


display_errors = on


(php.ini에 대한 액세스 권한이 없는 경우 .htaccess에이 줄을 넣는 것도 작동 할 수 있습니다) :


php_flag display_errors 1


8. 문자열을 받아서 지정된 문자 / 문자열로 시작하거나 끝나는 경우 반환하는 두 개의 함수를 작성하는 방법은 무엇입니까? 


대답: 


다음과 같이 할 수 있습니다.


function startsWith($haystack, $needle)
{
     $length = strlen($needle);
     return (substr($haystack, 0, $length) === $needle);
}

function endsWith($haystack, $needle)
{
    $length = strlen($needle);
    if ($length == 0) {
        return true;
    }

    return (substr($haystack, -$length) === $needle);
}


정규식을 사용하지 않으려면 이것을 사용하십시오.


대체 답변 : 


substr_compare 함수를 사용하여 다음으로 시작 및 끝을 확인할 수 있습니다.


function startsWith($haystack, $needle) {
    return substr_compare($haystack, $needle, 0, strlen($needle)) === 0;
}
function endsWith($haystack, $needle) {
    return substr_compare($haystack, $needle, -strlen($needle)) === 0;
}


9. PHP에서 리디렉션을 만드는 방법은 무엇입니까? 


대답: 


i. Basic answer 


header() 함수를 사용하여 새 HTTP 헤더를 보낼 수 있지만 이는 HTML 또는 텍스트 이전에 (예를 들어 <! DOCTYPE ...> 선언 이전에) 브라우저로 보내야 합니다.


header('Location: '.$newURL);


ii. Important details die() or exit() 


header("Location: http://example.com/myOtherPage.php");
die();


die() 또는 exit()를 사용해야 하는 이유 : The Daily WTF


절대 또는 상대 URL 


2014 년 6 월부터 절대 및 상대 URL을 모두 사용할 수 있습니다. 절대 URL 만 허용 된 이전 RFC 2616을 대체 한 RFC 7231을 참조하십시오.


상태 코드 


PHP의 "위치"헤더는 여전히 HTTP 302 리디렉션 코드를 사용하지만 사용해야 하는 코드는 아닙니다. 301 (영구 리디렉션) 또는 303 (기타) 중 하나를 고려해야 합니다.


참고 : W3C는 303 헤더가“많은 HTTP / 1.1 이전 사용자 에이전트와 호환되지 않는다고 언급합니다. 현재 사용되는 브라우저는 모두 HTTP / 1.1 사용자 에이전트입니다. 스파이더 및 로봇과 같은 다른 많은 사용자 에이전트에는 해당되지 않습니다.


iii. Documentation 


HTTP 헤더와 PHP의 header() 함수



iv. Alternatives 


http_redirect($ url)의 대체 방법을 사용할 수 있습니다. PECL 패키지 pecl을 설치해야 합니다.


v. 도우미 기능 


이 기능은 303 상태 코드를 포함하지 않습니다.


function Redirect($url, $permanent = false)
{
    header('Location: ' . $url, true, $permanent ? 301 : 302);

    exit();
}

Redirect('http://example.com/', false);


이것은 더 유연합니다.


function redirect($url, $statusCode = 303)
{
   header('Location: ' . $url, true, $statusCode);
   die();
}


vi. 해결 방법 


언급했듯이 header() 리디렉션은 아무것도 작성되기 전에 만 작동합니다. HTML 출력 중에 호출되면 일반적으로 실패합니다. 그런 다음 다음과 같은 HTML 헤더 해결 방법 (매우 전문적이지 않습니다!)을 사용할 수 있습니다.


<meta http-equiv="refresh" content="0;url=finalpage.html">


또는 JavaScript 리디렉션도 가능합니다.


window.location.replace("http://example.com/");


대체 답변 : 


header() 함수를 사용하여 HTTP 위치 헤더를 보냅니다.


header('Location: '.$newURL);


어떤 사람들이 생각하는 것과는 반대로 die ()는 리디렉션과 관련이 없습니다. 정상적인 실행 대신 리디렉션 하려는 경우에만 사용하십시오. example.php 파일 :


<?php
    header('Location: static.html');
    $fh = fopen('/tmp/track.txt', 'a');
    fwrite($fh, $_SERVER['REMOTE_ADDR'] . ' ' . date('c') . "\n");
    fclose($fh);
?>


세 번의 실행 결과 :


bart@hal9k:~> cat /tmp/track.txt
127.0.0.1 2009-04-21T09:50:02+02:00
127.0.0.1 2009-04-21T09:50:05+02:00
127.0.0.1 2009-04-21T09:50:08+02:00


재개 — 의무적 인 die () / exit ()는 실제 PHP와 관련이 없는 도시의 전설입니다. 클라이언트가 Location : 헤더를 "존중"하는 것과는 아무 관련이 없습니다. 헤더를 보내도 사용되는 클라이언트에 관계없이 PHP 실행이 중지되지 않습니다.


10. PHP에서 암호를 해싱 하기 위해 bcrypt를 어떻게 사용합니까? 


대답: 


bcrypt는 (구성 가능한 라운드 수를 통해) 하드웨어로 확장 가능한 해싱 알고리즘입니다. 속도가 느리고 여러 차례 진행되므로 공격자가 암호를 해독 할 수 있도록 막대한 자금과 하드웨어를 배치해야 합니다. 암호 단위 솔트 (bcrypt REQUIRES 솔트)에 추가하면 터무니없는 자금이나 하드웨어 없이는 공격이 사실상 불가능하다는 것을 확신 할 수 있습니다.


bcrypt는 Eksblowfish 알고리즘을 사용하여 암호를 해시합니다. Eksblowfish와 Blowfish의 암호화 단계는 정확히 동일하지만 Eksblowfish의 주요 일정 단계는 후속 상태가 솔트와 키 (사용자 암호)에 의존하도록 보장하며 둘 다 알지 못하면 상태를 미리 계산할 수 없습니다. 이 키 차이로 인해 bcrypt는 단방향 해싱 알고리즘입니다. 솔트, 반올림 및 키 (비밀번호)를 알지 못하면 일반 텍스트 비밀번호를 검색 할 수 없습니다. [출처]


bcrypt 사용 방법 : 


PHP> = 5.5-DEV 사용 


이제 암호 해싱 기능이 PHP> = 5.5에 직접 빌드 되었습니다. 이제 password_hash()를 사용하여 모든 암호의 bcrypt 해시를 만들 수 있습니다.


<?php
// Usage 1:
echo password_hash('rasmuslerdorf', PASSWORD_DEFAULT)."\n";
// $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
// For example:
// $2y$10$.vGA1O9wmRjrwAVXD98HNOgsNpDczlqm3Jq7KnEd1rVAGv3Fykk1a

// Usage 2:
$options = [
  'cost' => 11
];
echo password_hash('rasmuslerdorf', PASSWORD_BCRYPT, $options)."\n";
// $2y$11$6DP.V0nO7YI3iSki4qog6OQI5eiO6Jnjsqg7vdnb.JgGIsxniOn4C


기존 해시에 대해 사용자가 제공 한 비밀번호를 확인하려면 다음과 같이 password_verify ()를 사용할 수 있습니다.


<?php
// See the password_hash() example to see where this came from.
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';

if (password_verify('rasmuslerdorf', $hash)) {
    echo 'Password is valid!';
} else {
    echo 'Invalid password.';
}


PHP> = 5.3.7, <5.5-DEV 사용 (또한 RedHat PHP> = 5.3.3) 


GitHub에는 원래 C로 작성된 위 함수의 소스 코드를 기반으로 생성 된 호환성 라이브러리가 있으며 동일한 기능을 제공합니다. 호환성 라이브러리가 설치되면 사용법은 위와 동일합니다 (아직 5.3.x 브랜치에 있는 경우 축약 형 배열 표기법 제외).


PHP <5.3.7 사용 (지원 중단됨) 


crypt () 함수를 사용하여 입력 문자열의 bcrypt 해시를 생성 할 수 있습니다. 이 클래스는 자동으로 솔트를 생성하고 입력에 대해 기존 해시를 확인할 수 있습니다. 5.3.7 이상의 PHP 버전을 사용하는 경우 내장 함수 또는 compat 라이브러리를 사용하는 것이 좋습니다. 이 대안은 역사적 목적으로 만 제공됩니다.


class Bcrypt{
  private $rounds;

  public function __construct($rounds = 12) {
    if (CRYPT_BLOWFISH != 1) {
      throw new Exception("bcrypt not supported in this installation. See http://php.net/crypt");
    }

    $this->rounds = $rounds;
  }

  public function hash($input){
    $hash = crypt($input, $this->getSalt());

    if (strlen($hash) > 13)
      return $hash;

    return false;
  }

  public function verify($input, $existingHash){
    $hash = crypt($input, $existingHash);

    return $hash === $existingHash;
  }

  private function getSalt(){
    $salt = sprintf('$2a$%02d$', $this->rounds);

    $bytes = $this->getRandomBytes(16);

    $salt .= $this->encodeBytes($bytes);

    return $salt;
  }

  private $randomState;
  private function getRandomBytes($count){
    $bytes = '';

    if (function_exists('openssl_random_pseudo_bytes') &&
        (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN')) { // OpenSSL is slow on Windows
      $bytes = openssl_random_pseudo_bytes($count);
    }

    if ($bytes === '' && is_readable('/dev/urandom') &&
       ($hRand = @fopen('/dev/urandom', 'rb')) !== FALSE) {
      $bytes = fread($hRand, $count);
      fclose($hRand);
    }

    if (strlen($bytes) < $count) {
      $bytes = '';

      if ($this->randomState === null) {
        $this->randomState = microtime();
        if (function_exists('getmypid')) {
          $this->randomState .= getmypid();
        }
      }

      for ($i = 0; $i < $count; $i += 16) {
        $this->randomState = md5(microtime() . $this->randomState);

        if (PHP_VERSION >= '5') {
          $bytes .= md5($this->randomState, true);
        } else {
          $bytes .= pack('H*', md5($this->randomState));
        }
      }

      $bytes = substr($bytes, 0, $count);
    }

    return $bytes;
  }

  private function encodeBytes($input){
    // The following is code from the PHP Password Hashing Framework
    $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';

    $output = '';
    $i = 0;
    do {
      $c1 = ord($input[$i++]);
      $output .= $itoa64[$c1 >> 2];
      $c1 = ($c1 & 0x03) << 4;
      if ($i >= 16) {
        $output .= $itoa64[$c1];
        break;
      }

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 4;
      $output .= $itoa64[$c1];
      $c1 = ($c2 & 0x0f) << 2;

      $c2 = ord($input[$i++]);
      $c1 |= $c2 >> 6;
      $output .= $itoa64[$c1];
      $output .= $itoa64[$c2 & 0x3f];
    } while (true);

    return $output;
  }
}



이 코드를 다음과 같이 사용할 수 있습니다.


$bcrypt = new Bcrypt(15);

$hash = $bcrypt->hash('password');
$isGood = $bcrypt->verify('password', $hash);



또는 Portable PHP Hashing Framework를 사용할 수도 있습니다.


11. PHP를 사용하여 올해를 얻는 방법은 무엇입니까? 


대답: 


date 또는 strftime을 사용할 수 있습니다. 이 경우 연도를 다르게 지정하는 로케일이 없는 한 어떤 일이 있어도 1 년은 1 년이므로 중요하지 않습니다. 예를 들면 다음과 같습니다.


<?php echo date("Y"); ?>


참고로 PHP에서 날짜를 포맷 할 때 기본값과 다른 로케일로 날짜를 포맷 할 때 중요합니다. 그렇다면 setlocale 및 strftime을 사용해야 합니다. 날짜에 대한 PHP 설명서에 따르면 :


다른 언어로 날짜 형식을 지정하려면 date() 대신 setlocale() 및 strftime() 함수를 사용해야 합니다. 


이 관점에서 응용 프로그램을 지역화 해야 할 가능성이 먼 경우에도 가능한 한 strftime을 사용하는 것이 가장 좋습니다. 문제가 되지 않는다면 가장 마음에 드는 것을 선택하세요.


결론적으로 



다음은 PHP에 대해 가장 자주 묻는 11 가지 질문입니다. 제안 사항이나 혼란이 있으면 아래에 의견을 말하십시오. 도움이 필요하시면 기꺼이 도와 드리겠습니다.


Truemark에서는 웹 및 모바일 앱 개발, 디지털 마케팅 및 웹 사이트 개발과 같은 서비스를 제공합니다. 따라서 도움이 필요하고 우리와 함께 일하고 싶다면 언제든지 저희에게 연락하십시오.


이 기사가 도움이 되었기를 바랍니다.


원본 출처 : DevPostbyTruemark


PHP