본문 바로가기
코드이그나이터와 php7와 mysql

크레이의 라라벨 도전기 #9. 되묻지마! 패스글 시스템

반응형

※ 이 게시글은 크레이의 IT개발 관련 성장기를 다루고 있습니다. 관련지식이 약간 있어야 이해되실 수 있습니다. 가벼운 마음으로 읽어보시면서 흥미가 생기고 의욕이 생긴다면? 개발자의 자질이 있으신 겁니다 :)

유튜브를 시청하다 보면 예상 못할만한 무대를 보게 되는 경우가 종종 있는데요.
'안젤리카 헤일'이라는 소녀의 갓 텔런트 무대 영상 하나 올려드립니다.
마치 '모아나' 주인공같은 느낌도 드네요.

들으면서 보시면 지루함이 훨씬 급감하실 겁니다 :)

"기능이 있는교? 없는교?"

라라벨에 찾고자 하는 기능이 확인되지 않는다면 어떻게 해야 할까요?
뭐 계속 찾아보면 발견할 수도 있지만 개발자답게 새로 만드는 게 사실 개발자다운 방법입니다 :)

프레임워크 기본 기능에만 의지하다 보면 개발감각이 떨어지거든요.
이번 시간에는 글을 수정하면서 거치는 패스워드 인증 게시글을
한번 패스워드 입력하면
다음 번에 묻지 않는,
이름을 붙이자면 '되묻지마! 패스글 시스템' 을 공유드리겠습니다.

이 게시글은 아래 게시글에 이어서 연재되는 글입니다.
https://itadventure.tistory.com/609

 

크레이의 라라벨 도전기 #8. 레이아웃 템플릿 + 폼POST + 검증 한글화

※ 이 게시글은 크레이의 IT개발 관련 성장기를 다루고 있습니다. 관련지식이 약간 있어야 이해되실 수 있습니다. 가벼운 마음으로 읽어보시면서 흥미가 생기고 의욕이 생긴다면? 개발자의 자질

itadventure.tistory.com

반응형

미래박스 서비스는 회원가입 없이 게시글을 패스워드와 함께 등록, 관리하는 서비스입니다.
( 뭐 나중에 회원관리를 넣기는 할 거지만요 ㅎ.. )

그러다 보니 글을 수정할 때는 입력했던 패스워드를 다시 입력해야 수정이 가능한데요.
그러다 보니 글을 또 다시 수정할 때도 패스워드를 입력해야 합니다.

한번 패스워드를 입력한 글은 컴퓨터가 기억했다가 다음에는 '통과~'시켜주면 좋을텐데 말이지요.
여러가지 방법이 있겠지만 쿠키는 해킹의 위험이 있고,
그보다는 '세션'을 활용한 방법이 좋습니다.

세션에 배열 저장하기

열었던 글을 배열에 차곡 차곡 쌓아서 세션에 보관하는 방법으로 하면 안전한데요.
하지만 '세션'은 기본적으로 배열을 지원하지 않습니다.

어떤 방법이 좋을까 찾아보다 PHP 에 '시리얼라이즈'라는 기능이 있는 것을 처음 알아냈는데요.
배열변수를 알아볼 수 있을만한 수준의 문장으로 암호화(?)시켜주는 기능입니다.

예를 들면 아래 php 배열 변수를 시리얼라이즈하면,

$data = array('a', 'b', 'c', 1, 2, 3);
echo serialize($data);

아래 한줄의 문장으로 줄여줍니다. 암호같지요? 근데 암호는 아닙니다 :)

a:6:{i:0;s:1:"a";i:1;s:1:"b";i:2;s:1:"c";i:3;i:1;i:4;i:2;i:5;i:3;}

a:6: 은 배열요소가 6개이고, 중괄호 여는 기호 { 부터 시작, 중괄호 닫는 기호 } 가 배열 끝이 됩니다.
i:0;은 배열의 첫째 요소, 그 내용 s:1:"a"; 은 문자열 1글자, "a"를 의미하고,
i:3;은 배열의 넷째 요소, 그 내용 i:1; 은 정수형에 값이 1이라는 의미입니다.
차근 차근 잘 뜯어보면 그 내용을 이해할 수 있지요.

이처럼 배열을 하나의 문장으로 변환하는 serialize() 함수로 게시글 목록 배열을 세션에 저장할수 있고,
그 반대로 unserialize() 함수로 문장에서 다시 배열로 변환하는 언시리얼라이즈 함수가 있습니다.

지난 시간 Box 데이터 베이스 모델에 이 기능들을 추가 적용해보았는데요.
되묻지마! 패스글 시스템 소스는 아래와 같습니다.

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;

    :
 
class Box extends Model
{
    protected $fillable = ['title', 'writer', 'pwd', 'body', 'opendate'];
	// 세션명
	private static $passedbox_name="passBox";
	
	private static function get_passbox($session)
	{
		$passedBox = unserialize(session()->get(SELF::$passedbox_name));
		if($passedBox==false)$passedBox=array();
		return $passedBox;
	}
	
	// 패스워드를 입력, 글을 오픈했는지 여부
	public static function chk_passbox($session, $number)
	{
		$passedBox = SELF::get_passbox($session);
		if(array_key_exists($number, $passedBox))return true;
		return false;
	}
	
	// 패스워드를 입력, 글이 오픈되면 저장
	public static function add_passbox($session, $number)
	{
		$passedBox = SELF::get_passbox($session);
		$passedBox[$number]=true;		
		session()->put(SELF::$passedbox_name, serialize($passedBox));
	}

	// 패스워드를 입력, 글이 삭제되면 삭제
	public static function del_passbox($session, $number)
	{
		$passedBox = SELF::get_passbox($session);
		unset($passedBox[$number]);
		session()->put(SELF::$passedbox_name, serialize($passedBox));
	}
            :
            :

패스워드 인증을 거친 게시글 목록은 'passBox' 라는 세션명으로 저장하기 위해
프로퍼티(속성) 변수 $passedbox_name 를 정의하였습니다.

private static $passedbox_name="passBox";

get_passbox() 는 세션에 저장된 글 목록을 불러오는 메소드 함수입니다.
세션에 저장된 글 목록을 받아와 언시리얼라이즈해서 배열로 리턴하지만,
맨 처음이라면 세션변수가 없기 때문에 그 때는 공백 배열을 리턴합니다.

chk_passbox() 메소드 함수는 파라미터로 글번호를 넘겨주는데요,
해당 글 번호가 되묻지마! 글인지를 확인하고 가부 여부를 true/false 값으로리턴합니다.

add_passbox() 메소드 함수 또한 파라미터로 글번호를 넘겨주는데요.
해당 글 번호를 되묻지마! 글목록 세션에 저장합니다. 리턴값은 없습니다.

del_passbox() 메소드 함수는 그 반대로 되묻지마! 글번호를 글 목록 세션에서 삭제합니다.

이 4개의 메소드를 준비했으니 본격적으로 기능을 활용해보도록 하지요.

글 수정하기

지난 게시글에서 글을 작성해보았으니 이번에는 글을 수정해보도록 하겠습니다.
글을 수정할 때는 글 목록에서 연필 아이콘을 클릭하면 되는데요.

수정 버튼의 태그는 아래와 같습니다. /box/edit/글번호 주소로 연결해 주지요.

<i style="cursor:pointer;" class="bi bi-pen" 
	onclick="location.href='{{ url('/box/edit/' . $box->id ) }}'"></i>

라우터에서는 이를 BoxController 컨트롤러의 edit 메소드로 연결해 주는데요

Route::get('/box/edit/{id}', 'BoxController@edit');

이 때 전달받은 {id} 글번호를 메소드 파라미터에 함께 넘겨줍니다.

BoxController::edit() 메소드에서는 드디어 되묻지마! chk_passBox() 메소드를 사용하는데요.

        :
class BoxController extends Controller
{
        :
	// 글 편집
    public function edit($id, Request $request)
    {
        // 보안 : 세션 갱신
        $request->session()->regenerate();

        // 패스워드로 열었던 게시글인가?
        if( !Box::chk_passbox($request->session(), $id) )
        {
            // 아니면 패스워드 인증
            return view('box.editpass', ['id'=>$id]);
        }
        return view('box.edit', [ 'box'=>Box::get_one($id)]);
    }

패스워드로 인증을 거쳤는지를 검사해서 아직 인증을 거친적이 없으면 패스워드를 입력하는 뷰(box.editpass)를, 인증을 거쳤다면 바로 글을 수정할 수 있는 뷰(box.edit)를 표시합니다.

아직 패스워드 인증을 안 거쳤다고 가정하면 box.editpass  뷰로 이동해서 패스워드를 입력받는데요.

<form method='post' action='/box/editpass/{{ $id }}'>
    @csrf
    <div class="form-floating mb-1">
      <input type="password" class="form-control" 
        id="pwd" name="pwd" placeholder="비밀번호">
      <label for="pwd">비밀번호</label>
    </div>

    <button type="submit" class="btn btn-primary">비밀번호 확인!</button>
    <button type="button" class="btn btn-primary" 
      onclick="location.href='/box'">목록</button>

</form>

패스워드 입력 후 비밀번호 확인 버튼을 클릭하면, /box/editpass/글번호 URL 로 비밀번호가 맞는지 확인을 위해 post 전송을 합니다.

라우터에서는 BoxController 컨트롤러의 editpass 메소드로 내용을 전달하고,

Route::post('/box/editpass/{id}', 'BoxController@editpass');

editpass 메소드는 패스워드가 맞는지 확인하고 틀리면 이전 페이지로 이동하고,
맞으면 box.edit 뷰로 이동합니다.

// 글 수정 패스워드 확인 액션
public function editpass($id, Request $request)
{		
    // 보안 : 세션 갱신
    $request->session()->regenerate();

    // 패스워드 일치 확인
    if(!Box::chk_pass($id, $request->get('pwd')))
    {
        return view('box.editpass', ['id'=>$id])
            ->withErrors([
                "password_fail"=>"패스워드가 일치하지 않습니다."
            ]);
    }

    // 성공했으니 세션 종료시까지 안 물어봄
    Box::add_passbox($request->session(), $id);

    return view('box.edit', [ 'box'=>Box::get_one($id)] );
}

그러면서 Box::add_passbox 를 동시에 실행해 되묻지마! 게시글로 등록해버리는 것이지요.

Box::add_passbox($request->session(), $id);

이제 드디어 게시글 편집 페이지로 진입했군요.

@extends('box.layout')

@section('description', '글의 내용을 수정하고 싶으신가요?')

@section('content')

@if ($errors->any())
	@foreach ($errors->all() as $error)
		<div class="alert alert-danger">
			{{ $error }}
		</div>
	@endforeach
@endif

	<form method='post' action='/box/editpost/{{ $box->id }}'>
		@csrf
		<div class="form-floating mb-1">
		  <input type="text" class="form-control" id="title" name="title" 
            placeholder="제목" value="{{ $box->title }}" required>
		  <label for="title">제목</label>
		</div>
		<div class="form-floating mb-1">
		  <input type="text" class="form-control" id="writer" name="writer" 
            placeholder="닉네임" value="{{ $box->writer }}">
		  <label for="writer">닉네임</label>
		</div>
		<div class="form-floating mb-3">
			<textarea class="form-control" id="body" name="body" rows="3" 
            placeholder="일주일 뒤 공개될 숨김글을 작성하세요!" 
              style="height: 100px;">{{ $box->body }}</textarea>
			<label for="body">일주일 뒤 공개될 숨김글을 작성하세요!</label>
		</div>
		
		<button type="submit" class="btn btn-primary">수정 끝!</button>
		<button type="button" class="btn btn-primary"
        onclick="location.href='/box'">목록</button>
  
	</form>

@endsection

이제 글 내용을 수정하고 '수정 끝!' 버튼을 누르면 내용이 변경되는 것은 글작성과 별반 다를 것은 없습니다.

글 삭제 부분도 비슷한 원리로 작동되는데요 핵심은 모두 설명드린것 같아 굳이 길게 설명할 것 없이
이제까지의 관련 모든 소스를 공개하는 것으로 글을 마칩니다 :)

전체소스

라우터 소스 ( routes/web.php )

// 글목록
Route::get('/box', 'BoxController@index');
// 신규 글 작성
Route::get('/box/write', 'BoxController@write');
// 신규 글 작성 액션
Route::post('/box/writepost', 'BoxController@writepost');
// 글 수정
Route::get('/box/edit/{id}', 'BoxController@edit');
// 글 수정 패스워드 확인
Route::post('/box/editpass/{id}', 'BoxController@editpass');
// 글 수정 액션
Route::post('/box/editpost/{id}', 'BoxController@editpost');
// 글 삭제
Route::get('/box/deletepass/{id}', 'BoxController@deletepass');
// 글 삭제 액션
Route::post('/box/deletepost/{id}', 'BoxController@deletepost');

모델소스 ( app/Box.php )

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Carbon\Carbon;
use App\HangulTime;

// use Illuminate\Support\Facades\Hash;
use Hash;

// use Illuminate\Support\Facades\DB;
// use DB;
 
class Box extends Model
{
    protected $fillable = ['title', 'writer', 'pwd', 'body', 'opendate'];
	// 세션명
	private static $passedbox_name="passBox";
	
	private static function get_passbox($session)
	{
		$passedBox = unserialize(session()->get(SELF::$passedbox_name));
		if($passedBox==false)$passedBox=array();
		return $passedBox;
	}
	
	// 패스워드를 입력, 글을 오픈했는지 여부
	public static function chk_passbox($session, $number)
	{
		$passedBox = SELF::get_passbox($session);
		if(array_key_exists($number, $passedBox))return true;
		return false;
	}
	
	// 패스워드를 입력, 글이 오픈되면 저장
	public static function add_passbox($session, $number)
	{
		$passedBox = SELF::get_passbox($session);
		$passedBox[$number]=true;		
		session()->put(SELF::$passedbox_name, serialize($passedBox));
	}

	// 패스워드를 입력, 글이 삭제되면 삭제
	public static function del_passbox($session, $number)
	{
		$passedBox = SELF::get_passbox($session);
		unset($passedBox[$number]);
		session()->put(SELF::$passedbox_name, serialize($passedBox));
	}

	// 글목록
	public static function list_order()
	{
		$boxes = SELF::orderBy('created_at', 'desc')->paginate(5);
		// 날짜에 따른 가공
		$today=Carbon::now()->timezone('Asia/Seoul');
		for($i=0;$i<count($boxes);++$i)
			if($today < $boxes[$i]->opendate)
			{
				$boxes[$i]->body="<i class='bi bi-body-text'></i>개봉전";
				$boxes[$i]->opendate = HangulTime::get($boxes[$i]->opendate) . "후";
			}
			else {
				$boxes[$i]->opendate = "";
			}
		return $boxes;
	}
	
	// 글정보
	public static function get_one($id)
	{
		return SELF::where('id', $id)
			->orderBy('created_at', 'desc')
			->limit(1)
			->get()[0];
	}
	
	public static function write(Request $request)
	{
		// 글 저장
		SELF::create([
			'title' => $request->get('title'),
			'writer' => $request->get('writer'),
			'pwd' => bcrypt($request->get('pwd')),
			'body' => $request->get('body'),
			'opendate'=> Carbon::now()->timezone('Asia/Seoul')->addDays(7)
		]);
	}
	
	public static function update_one($id, Request $request)
	{
		// 글 저장
		SELF::where('id', $id)->update([
			'title' => $request->get('title'),
			'writer' => $request->get('writer'),
			'body' => $request->get('body')
		]);
	}

	// 패스워드 검증
	public static function chk_pass($id, $pass)
	{
		$box = SELF::get_one($id);
		return Hash::check(
			$pass, 
			$box->pwd
		);
	}	
}

컨트롤러 ( app/Http/Controllers/BoxController.php )

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Box;
use Carbon\Carbon;

class BoxController extends Controller
{	
	public function index(Request $request)
	{
		return view('box.index', [
			'boxes'=>Box::list_order()
		]);
	}
	
	public function write(Request $request)
	{
		// 보안 : 세션 갱신
		$request->session()->regenerate();
		return view('box.write');
	}
	
	public function writepost(Request $request)
	{
		$messages = [
			'title.required' => '제목을 입력하세요',
			'writer.required' => '작성자를 입력하세요',
			'pwd.required' => '패스워드를 입력하세요',
			'pwd.min' => '패스워드는 최소 6글자 이상입니다.',
			'pwd2.same' => '패스워드 확인이 일치하지 않습니다.',
			'body.required' => '본문을 입력하세요',
			'body.min' => '박스글은 100글자 이상 작성하셔야 합니다.'
		];

		// 유효성 검사
		$request->validate([
			'title' => 'required',
			'writer' => 'required',
			'pwd' => 'required|min:6',
			'pwd2' => 'same:pwd',
			'body' => 'required|min:100',
		 ], $messages);
		
		Box::write($request);
		
		return redirect('/box');
	}
	
	// 글 편집
	public function edit($id, Request $request)
	{
		// 보안 : 세션 갱신
		$request->session()->regenerate();
			
		// 패스워드로 열었던 게시글인가?
		if( !Box::chk_passbox($request->session(), $id) )
		{
			// 아니면 패스워드 인증
			return view('box.editpass', ['id'=>$id]);
		}
		return view('box.edit', [ 'box'=>Box::get_one($id)]);
	}
	
	// 글 수정 패스워드 확인 액션
	public function editpass($id, Request $request)
	{		
		// 보안 : 세션 갱신
		$request->session()->regenerate();
		
		// 패스워드 일치 확인
		if(!Box::chk_pass($id, $request->get('pwd')))
		{
			return view('box.editpass', ['id'=>$id])
				->withErrors([
					"password_fail"=>"패스워드가 일치하지 않습니다."
				]);
		}
		
		// 성공했으니 세션 종료시까지 안 물어봄
		Box::add_passbox($request->session(), $id);
		
		return view('box.edit', [ 'box'=>Box::get_one($id)] );
	}

	//  글수정 액션
	public function editpost($id, Request $request)
	{
		// 해킹방지 : 패스워드로 열었던 게시글인가?
		if( !Box::chk_passbox($request->session(), $id) )
		{
			// 아니면 패스워드 인증
			return view('box.editpass', ['id'=>$id]);
		}
		
		Box::update_one($id, $request);
		
		return redirect('/box');
	}

	//  글 삭제
	public function deletepass($id, Request $request)
	{
		// 글 삭제할 경우 무조건 패스워드 물어봄
		return view('box.deletepass', ['id'=>$id]);
	}

	// 글 삭제 패스워드 확인 액션
	public function deletepost($id, Request $request)
	{
		// 패스워드 일치 확인
		if(!Box::chk_pass($id, $request->get('pwd')))
		{
			return view('box.deletepass', ['id'=>$id])
				->withErrors([
					"password_fail"=>"패스워드가 일치하지 않습니다."
				]);
		}	
		return redirect('/box');
	}
}

뷰 - 레이아웃 ( resources/views/box/layout.blade.php )

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>미래박스</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-rbsA2VBKQhggwzxH7pPCaAqO46MgnOM80zW1RWuH61DGLwZJEdK2Kadq2F9CUG65" crossorigin="anonymous">
	<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.7.1/font/bootstrap-icons.css">
  </head>
  <body>
	<div class="container text-center">
		<div class="card my-4" style="width: 18rem;margin:0 auto;">
		  <img src="/img/fbox.png" class="card-img-top" alt="미래박스">
		  <div class="card-body">
			<h5 class="card-title">미래 박스</h5>
			<p class="card-text">@yield('description')</p>
		  </div>
		</div>
		
		@yield('content')
		
	</div>

	<nav class="navbar navbar-dark bg-secondary mt-4">
		<div class="container-fluid">
			<span class="navbar-brand mb-0 h1"><a href='https://itadventure.tistory.com' class='text-white' target='_blank'>Cray's side project</a></span>
		</div>
	</nav>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.2.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-kenU1KFdBIe4zVF0s0G1M5b4hcpxyD9F7jL+jjXkk+Q2h455rYXK/7HAuoJl+0I4" crossorigin="anonymous"></script>
  </body>
</html>

뷰 - 목록 ( resources/views/box/index.blade.php )

@extends('box.layout')

@section('description')
	일주일 후에 열려라! 친구들이 숨겨놓은 이야기를 만나보세요.
@endsection

@section('content')

	<table class="table">
	<tr class="table bg-primary text-white">
	<td>제목</td>
	<td>작성자</td>
	<td>오픈</td>
	<td></td>
	</tr>
	<?php $keycnt=1; ?>
	@foreach ($boxes as $box)
	<tr>
	<td>{{ $box->title }}</td>
	<td>{{ $box->writer }}</td>
	<td>{{ $box->opendate }}</td>
	<td>
		<i style="cursor:pointer;" class="bi bi-pen" 
			onclick="location.href='{{ url('/box/edit/' . $box->id ) }}'"></i>
		<i style="cursor:pointer;" class="bi bi-x-square-fill" 
			onclick="location.href='{{ url('/box/deletepass/' . $box->id ) }}'"></i>
	</td>
	</tr>
	<tr>
	<td colspan=4>
	
		<div class="accordion" id="accordionPanelsStayOpenExample">
		  <div class="accordion-item">
			<h2 class="accordion-header" id="panelsStayOpen-headingOne">
			  <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#panelsStayOpen-collapse{{ $keycnt }}" aria-expanded="false" aria-controls="panelsStayOpen-collapseOne">
				<i class="bi bi-archive-fill mx-1"></i>
				미래 상자에는 무슨 내용이 들어 있을까요 ?
			  </button>
			</h2>
			<div id="panelsStayOpen-collapse{{ $keycnt }}" class="accordion-collapse collapse" aria-labelledby="panelsStayOpen-headingOne">
			  <div class="accordion-body">
				{!! $box->body !!}
			  </div>
			</div>			
		  </div>
		</div>
	</td>
	</tr>
	<?php $keycnt++; ?>
	@endforeach
	</table>
	
	{{ $boxes->links() }}
	
	<button type="button" class="btn btn-primary" onclick="location.href='{{ url('/box/write') }}'">쓰삭 쓰삭</button>

@endsection

뷰 - 글쓰기 ( resources/views/box/index.blade.php )

@extends('box.layout')

@section('description', '일주일 후에 공개될 비밀상자 게시글을 작성해 보세요.')

@section('content')

@if ($errors->any())
	@foreach ($errors->all() as $error)
		<div class="alert alert-danger">
			{{ $error }}
		</div>
	@endforeach
@endif

	<form method='post' action='/box/writepost'>
		@csrf
		<div class="form-floating mb-1">
		  <input type="text" class="form-control" id="title" name="title" placeholder="제목" value="{{ old('title') }}" required>
		  <label for="title">제목</label>
		</div>
		<div class="form-floating mb-1">
		  <input type="text" class="form-control" id="writer" name="writer" placeholder="닉네임" value="{{ old('writer') }}">
		  <label for="writer">닉네임</label>
		</div>
		<div class="form-floating mb-1">
		  <input type="password" class="form-control" id="pwd" name="pwd" placeholder="비밀번호">
		  <label for="pwd">비밀번호</label>
		</div>
		<div class="form-floating mb-1">
		  <input type="password" class="form-control" id="pwd2" name="pwd2" placeholder="비밀번호 확인" required>
		  <label for="pwd2">비밀번호 확인</label>
		</div>
		<div class="form-floating mb-3">
			<textarea class="form-control" id="body" name="body" rows="3" placeholder="일주일 뒤 공개될 숨김글을 작성하세요!" style="height: 100px;">{{ old('body') }}</textarea>
			<label for="body">일주일 뒤 공개될 숨김글을 작성하세요!</label>
		</div>
		
		<button type="submit" class="btn btn-primary">쓰삭 끝!</button>
		<button type="button" class="btn btn-primary" onclick="location.href='/box'">목록</button>
  
	</form>

@endsection

뷰 - 패스워드 입력 ( resources/views/box/editpass.blade.php )

@extends('box.layout')

@section('description', '글을 수정하려면 패스워드를 입력해 주세요.')

@section('content')

@if ($errors->any())
	@foreach ($errors->all() as $error)
		<div class="alert alert-danger">
			{{ $error }}
		</div>
	@endforeach
@endif

	<form method='post' action='/box/editpass/{{ $id }}'>
		@csrf
		<div class="form-floating mb-1">
		  <input type="password" class="form-control" id="pwd" name="pwd" placeholder="비밀번호">
		  <label for="pwd">비밀번호</label>
		</div>
		
		<button type="submit" class="btn btn-primary">비밀번호 확인!</button>
		<button type="button" class="btn btn-primary" onclick="location.href='/box'">목록</button>
  
	</form>

@endsection

뷰 - 글 수정 ( resources/views/box/edit.blade.php )

@extends('box.layout')

@section('description', '글의 내용을 수정하고 싶으신가요?')

@section('content')

@if ($errors->any())
	@foreach ($errors->all() as $error)
		<div class="alert alert-danger">
			{{ $error }}
		</div>
	@endforeach
@endif

	<form method='post' action='/box/editpost/{{ $box->id }}'>
		@csrf
		<div class="form-floating mb-1">
		  <input type="text" class="form-control" id="title" name="title" placeholder="제목" value="{{ $box->title }}" required>
		  <label for="title">제목</label>
		</div>
		<div class="form-floating mb-1">
		  <input type="text" class="form-control" id="writer" name="writer" placeholder="닉네임" value="{{ $box->writer }}">
		  <label for="writer">닉네임</label>
		</div>
		<div class="form-floating mb-3">
			<textarea class="form-control" id="body" name="body" rows="3" placeholder="일주일 뒤 공개될 숨김글을 작성하세요!" style="height: 100px;">{{ $box->body }}</textarea>
			<label for="body">일주일 뒤 공개될 숨김글을 작성하세요!</label>
		</div>
		
		<button type="submit" class="btn btn-primary">수정 끝!</button>
		<button type="button" class="btn btn-primary" onclick="location.href='/box'">목록</button>
  
	</form>

@endsection

뷰 - 글 삭제 패스워드 입력 ( resources/views/box/deletepass.blade.php )

@extends('box.layout')

@section('description', '정말 삭제하시겠어요? 삭제하시려면 패스워드를 입력해 주세요.')

@section('content')

@if ($errors->any())
	@foreach ($errors->all() as $error)
		<div class="alert alert-danger">
			{{ $error }}
		</div>
	@endforeach
@endif

	<form method='post' action='/box/deletepost/{{ $id }}'>
		@csrf
		<div class="form-floating mb-1">
		  <input type="password" class="form-control" id="pwd" name="pwd" placeholder="비밀번호">
		  <label for="pwd">비밀번호</label>
		</div>
		<button type="submit" class="btn btn-primary">비밀번호 확인!</button>
		<button type="button" class="btn btn-primary" onclick="location.href='/box'">목록</button>
	</form>
	

@endsection

필요하신 분에게 도움이 되셨기를 바라며,
오늘도 찾아와 주신 모든 구독자님들께 감사드립니다 :)

반응형