Tag Archives: 병원

[WORDPRESS로 환자 DATABASE 만들기] #2. 환자별 자료 등록하기, Codex 이용

준비작업

#0. 환자별 자료등록을 위해 CPT로 medicaldata라는 type을 만들었다. 그리고 역시 Has Archive를 true로 했다. 일단 전체보기가 있으면 좋을 듯 하여.

#1. 환자별 자료 등록을 위해 content-patients.php에 코드에 링크를 걸어준다.

<tr><td><?=$pts_id?></td><td><a href='<?=get_site_url()?>/data_upload/<?=$pts_id?>'>자료 등록</a></td></tr>

#2. 일단 위의 링크처럼 전제조건은 /data_upload 라는 페이지가 우선 있어야 한다.

WPF를 통해 다음과 같이 페이지를 만들어줬다.

WPF를 통해 폼을 만들 때 Post setting에서 해당 post type을 ‘medicaldata’로 해줘야 한다

Untitled-1

일단 환자 ID 쓰는 부분은 없다.


Codex를 이용한 주소창을 통한 데이터 입력받기

Contents~.php를 바꾸고 난 뒤 archives를 보면, link 주소가 /data_upload/2016080304 등으로 되어있는데, 이 부분을 우리는 ID로 이용한다.

굳이 이렇게 안하고 data_upload?id=1111111 이럴수도 있는데, 이러면 멋있지 않으니까…

function.php 수정하여 Codex 규칙 적용

function add_rewrite_rules($rules) {
    $NewRules['data_upload/([^/]+)$'] = 'index.php?pagename=data_upload&pts_id=$matches[1]';
    $rules = $NewRules + $rules;
    return $rules;
}
// hook add_rewrite_rules function into rewrite_rules_array
add_filter('rewrite_rules_array', 'add_rewrite_rules');

function my_flush_rules(){
	$rules = get_option( 'rewrite_rules' );

	if ( ! isset( $rules['data_upload/([^/]+)$'] ) ) {
		global $wp_rewrite;
	   	$wp_rewrite->flush_rules();
	}
}

add_action( 'wp_loaded','my_flush_rules' );

코드는 의외로 간단하다. 정규표현식으로 data_upload/뒤에 붙은 문자를 원래 워드프레스 ‘페이지’로 들어가는 접근 경로로 이용해주는 것이다.

이 예제에서는 pid 라는 변수로 이용했다. pts_id 라는 변수로 했다. pid라는 변수는 포스트를 edit할때 그 포스트 아이디로 사용하기 때문이다.

<1>

function add_query_vars($vars) 
{   
    $vars[] = "pts_id"; 
    return $vars;
}

<2>

add_filter( 'init', 'add_more_query_var' );
function add_more_query_var()
{
    global $wp;
    $wp->add_query_var( 'pts_id' );
}

function.php에 pts_id라는 값을 사용할 것이 때문에 두번째 줄을 추가해준다. 아마도 php에서 $_GET[‘pts_id’] 라고 쓰던 것에 대한 내부적 처리일듯 하다.

(2017.05.28 : 2번째 방식이 더 잘 듣는 것 같다)

my_flush_rule 함수는 내가 정의한 codex 규칙이 없으면 flush(갱신이라고 해야하나?)를 하는데 이 함수가 없으면 적용이 안되더라. 위의 pid->pts_id로 수정하다 보니까 rule이 수정이 바로 안되는 현상이 발생. 그럴 땐 page.php에서

print_r( get_option(‘rewrite_rules’) ); 함수를 이용해서 rule이 잘 등록되었는지 확인, 잘 안되어있으면

global $wp_rewrite;
$wp_rewrite->flush_rules();

이 부분을 if 바깥쪽으로 빼서 강제로 한번 실행시켜 주면 된다.

 

Page.php 수정

#4.  그럼 이제 테마의 page.php 파일을 바꿔줄 것이다.

위의 codex처럼 되었으면 data_upload 페이지로 접근할 때만 pts_id 라는 변수가 있는 것이다.

따라서

if(isset($wp_query->query_vars['pts_id'])) 
	{
	    $pts_id = urldecode($wp_query->query_vars['pts_id']);
	    echo $pts_id;
	}

이 코드를 넣어주면 다음과 같이

Untitled-1

숫자가 잘 출력이 된다. pid 값이 옳은지 검증하는 부분은 잘 만들면 될 것 같고..

function.php 수정하여 Field 만들기

#4. 이제 저 값을 이용해 field를 만든다. hooking을 이용하면 된다.

용어의 헷갈림을 피하기 위해 pts_id를 pts_rec_id로 바꾸는 작업등 몇가지만 했다.

특이사항은 global $pts_id 인데, 이건 page.php파일에서 정의된 $pts_id를 이용하기 위함이다. 우연히 넣어봤는데 잘된다..아마 loading 순서가 page.php 이후에 function이 읽히는건가?…

function medical_record_pid( $form_id, $post_id, $form_settings ) { 
    if ( $post_id ) {     //포스팅 수정일 경우
    	//echo "포스트 수정 ".$post_id;
        $em = get_post_meta($post_id, 'pts_rec_id');        
        $pts_rec_id  = $em[0];
    }
    else                  //신규 포스팅의 경우
    {
        global $pts_id;
    	$pts_rec_id = $pts_id;
    }
    ?>    
 <li class="wpuf-el pts_id" data-label="DB 등록번호">        <div class="wpuf-label">
            <label for="wpuf-pts_id">DB 등록번호 <span class="required">*</span></label>
        </div>
        
        <div class="wpuf-fields">
            <input class="textfield wpuf_pts_id_28" id="pts_id" readonly="readonly" type="text" data-required="yes" data-type="text" name="pts_rec_id" placeholder="" value="<?=$pts_rec_id ?>" size="40"  />
            <span class="wpuf-help"></span>

                    </div>

                <script type="text/javascript">

            wpuf_conditional_items.push();

        </script>
        </li>
    <?php
}
add_action( 'medical_record_pid_hook', 'medical_record_pid',10,3);

/**** 이하는 DB저장을 위한 함수 ****/
function wpufe_update_record_pid( $post_id ) {
    if ( isset( $_POST['pts_rec_id'] ) ) {
        update_post_meta( $post_id, 'pts_rec_id', $_POST['pts_rec_id']); 
    }
}
 
add_action( 'wpuf_edit_post_after_update', 'wpufe_update_record_pid' );
add_action( 'wpuf_add_post_after_insert', 'wpufe_update_record_pid' );

이렇게 하면 다음과 같이Untitled-1

잘들어가지는 것 확인. 이제 예시로 몇개 작성해본다.

 

Medicaldata Archive 수정

이제 medicaldata 아카이브를 봐본다.

Untitled-1

값이 잘 들어왔다. 이 부분을 바꾸는 것은 다시 첫번째 포스팅의 반복이다.

#6.

테마의 archive-patients.php를 복사해서 archive-medicaldata.php로 만들고,

content-medicaldata.php를 만들어서 살짝만 수정해준다.

	<?php 	
			$pts_rec_id = get_post_meta($post->ID, 'pts_rec_id')[0];			
			$title = get_the_title($post->ID);
	?>
	<tr><td><?=$pts_rec_id?></td><td><?=$title?></td></tr>

이렇게 해서

Untitled-1

하면 완성, 아래 4개는 잘못만들어진 데이터다. 막 만들다보니..


다음 포스팅 에서는 & References

#1. pts_id 와 pts_rec_id가 동일한 data만 추출하는 것. 그래야 그 환자의 자료만 볼 수 있을테니까.

#2. 레코드 삭제버튼

#3. 환자 데이터를 삭제할때 하위 레코들도 함께 삭제하기(귀찮을 것 같다)

#4. 환자등록시 주민등록번호를 받아서 암호화 시켜 저장하고, 주민등록번호로 환자 record를 찾을 수 있게 하기.

암호화는 gnuboard시절에는 md4 알고리즘을 썼었는데,

http://www.openeg.co.kr/329 를 보니, SHA-1, MD5는 권고하지 않는다고?..

만약 폐쇄된 네크워크에서 데이터베이스를 구성하려면 MD5나 SHA-1로도 어느정도 구색이 나겠지만,

그리하여 검색하다보니

Password Hashing and Encryption In PHP; MD5, SHA1, SHA256, BCrypt

사이트에 좋은 예제가 있다.

Salts를 이용한 security라고, 결국에는 데이터 자체가 훔쳐지는 것은 어떻게 하지 못해도, 그 데이터의 원래 내용이 뭔지 모르게 함에 그 목적이 있는 것이니.

 

http://www.yes24.com/24/goods/8921236?scode=032&OzSrank=1

개인적으로 전문적인 컴퓨터 지식이 많지 않은 나같은 일반인이 암호화에 대해 이해하기로는 링크를 걸은 ‘미래를 바꾼 아홉 가지 알고리즘’ 이라는 책을 강력히 추천한다. 여기에 암호화 파트를 보면 대강이나마 어떤식으로 암호화가 구현되는지 알 수 있을 것이다.

[WordPress로 환자 Database 만들기] #1. 등록번호 생성, 환자 명단 스킨

Intro

한 5년 전쯤 zeroboard, gnuboard 등을 이용해서 병원내 DB를 만들었는데, 당시에 테이블구조를 바꾸고 별별 짓을 다했던 기억이난다.

사실 이런 일들이 매우 비효율적인데, 아무리 기존의 툴을 이용한다고 하더라도 로직이 완전히 새로 구성되어야 하기 떄문이다.

WordPress로 몇몇 소소한 프로젝트를 하다보니, 이거로 DB를 만드는 것이 가능하겠더라 싶어서, 하나하나 기록을 남기면서 진행해보고자 한다. 최종적으로 결과물이 나올지는 나도 잘 모르겠지만.


Plugins

일단 다음과 같은 Plugin들을 사용한다.

  1.  Custom Post Type UI (CPT UI)
  2.  WP User Frontend Pro (WPF)

WPF; 150불 정도에 구입했다. Hooking 등의 고급 elements가 필요했다

CPT UI를 사용하는 이유는 page라고 하는 것을 하나의 ‘record’라고 본다면, 하나의 ‘patient’ 와 종속된 여러개의 ‘patient_record’ 구조를 만들어낼 수 있을 것 같다. 두 다른 레코드는 메타값으로 연결하면 되기 때문에.

또하나는 CPT UI에서 각 custom type에 대한 각각의 archieve-(type).php 로 스킨을 나눌 수 있다. 즉 back-end가 워드프레스로 쉽게 생성이되면, 사용자는 front-end만 구성해주면 되기 때문에.

또한 각각의 레코드는 searching을 각각 구성해버리면 된다.


환자 ID 생성

CPT와 WPF 세팅

일단 이번 포스팅에서는 DB내 환자 ID 생성하는 방법은 다음과 같이 한다.

  • CPT UI에서 ‘Patients’라는 Post Type을 생성 (Has Archive를 True로 세팅해둔다 – 나열이 가능하게 하기 위함)
  • 그리고 이 Post Type을 작성하기 위한 Form을 WPF에서 생성해주는데, 과감히 Post Title과 Post Body를 제외하고 일단 ID 창을 만드는데, Hooking을 이용한다.
  • hook_patient_id_making라는 Hook name을 세팅했다.

  • 관련 함수를 해당테마의 function.php을 수정한다.
function making_id( $form_id, $post_id, $form_settings ) { 
    if ( $post_id ) {     //포스팅 수정일 경우    	
        $em = get_post_meta($post_id, 'pts_id');        
        $pts_id  = $em[0];
    }
    else                  //신규 포스팅의 경우
    {
        $blogtime = current_time( 'mysql' ); 
    	list( $today_year, $today_month, $today_day, $hour, $minute, $second ) = split( '([^0-9])', $blogtime );		
    	$args = array( 
    		'year' => $today_year,  
    		'monthnum' => $today_month, 
    		'day' => $today_day,    		
    		'post_type' => 'patients'
    		);
    	echo "Today : ".$today_year." ".$today_month." ".$today_day;
    	$the_query = new WP_Query( $args );    	
    	echo "<h2>금일등록된 환자 숫자 : ".$the_query->found_posts."</h2>";
    	$pts_id = sprintf("%04d%02d%02d%02d",$today_year,$today_month,$today_day,$the_query->found_posts+1);
    }
    ?>    
 <li class="wpuf-el pts_id" data-label="DB 등록번호">        <div class="wpuf-label">
            <label for="wpuf-pts_id">DB 등록번호 <span class="required">*</span></label>
        </div>
        
        <div class="wpuf-fields">
            <input class="textfield wpuf_pts_id_28" id="pts_id" readonly="readonly" type="text" data-required="yes" data-type="text" name="pts_id" placeholder="" value="<?=$pts_id ?>" size="40"  />
            <span class="wpuf-help"></span>

                    </div>

                <script type="text/javascript">

            wpuf_conditional_items.push();

        </script>
        </li>
    <?php
}
add_action( 'hook_patient_id_making', 'making_id',10,3);

/**** 이하는 DB저장을 위한 함수 ****/
function wpufe_update_pid( $post_id ) {
    if ( isset( $_POST['pts_id'] ) ) {
        update_post_meta( $post_id, 'pts_id', $_POST['pts_id']); 
    }
}
 
add_action( 'wpuf_edit_post_after_update', 'wpufe_update_pid' );
add_action( 'wpuf_add_post_after_insert', 'wpufe_update_pid' );

(1) blogtime = current_time( ‘mysql’ );
list( $today_year, $today_month, $today_day, $hour, $minute, $second ) = split( ‘([^0-9])’, $blogtime );

금일 날짜를 받아서

(2) $args = array(
‘year’ => $today_year,
‘monthnum’ => $today_month,
‘day’ => $today_day,
‘post_type’ => ‘patients’
);

쿼리를 만든다. 즉 금일 등록된 ‘patients(custom type)’의 개수를 세기 위함

(3) echo “Today : “.$today_year.” “.$today_month.” “.$today_day;
$the_query = new WP_Query( $args );

$the_query->found_posts

found_post가 찾아진 갯수

(4) ID를 $pts_id = sprintf(“%04d%02d%02d%02d”,$today_year,$today_month,$today_day,$the_query->found_posts+1);

즉 2016080301 이런식으로 만드는 것이다. 그럼 중복되지 않으니까.

이하는 폼 html 태그와 DB저장을 위한 후킹 부분이다.

Patient Archive 확인

테스트를 위해 환자를 막 등록해본다.(CPT UI에서 has_archive = true로 하는 것을 잊지 말것)

Untitled-1

  • 일단 이렇게 등록을 하고 나면, 이제 archive를 확인할 것이다.
  • CPT가 제대로 됐다면 아래처럼 눌렀을 때 리스트가 나온다.

http://127.0.0.1/wp/archives/patients

Untitled-2

(위의 예시와는 다를 수 있다. 당연한 얘기지만 나는 patient 등록 form에 post_title과 post_body가 없으니 아무내용 없는 빈페이지 뿐인 것이다)

Cutsom Archive 페이지 만들기

얘기했듯이 기존의 page와 구분되는 patients만 보는 페이지를 만들어보겠다.

  • 이를 위해 테마폴더의 archive.php를 archive-patients.php로 복사를 한다. 그리고 소스의 이 부분을 바꾼다.

get_template_part( ‘template-parts/content’, get_post_format() );

get_template_part( ‘template-parts/content’, $post->post_type);

get_post_format() 이 null값이 나오더라. 우리는 patients에 해당하는 부분만 만들것이니까 $post->post_type으로 바꾸면 ‘patients‘ 라는 문자열로 잘 넘어간다.

그리고 테마폴더의 template_parts의 content-single을 content-patients.php로 복사해서 원하는 방법으로 고치는데, 이렇게 해보았다. (즉 custom type 의 이름이 계속 쓰이는 구조이다)

일단 archive-patients.php에서는 <table></table>로 루프를 감싸고,

<table>			
			<?php
			// Start the Loop.
			while ( have_posts() ) : the_post();				
				/*
				 * Include the Post-Format-specific template for the content.
				 * If you want to override this in a child theme, then include a file
				 * called content-___.php (where ___ is the Post Format name) and that will be used instead.
				 */
				get_template_part( 'template-parts/content', $post->post_type/*get_post_format()*/ );

			// End the loop.
			endwhile;
			?></table><?php

content-patients.php를 다음처럼 만든다. (이정도면 사실 archive에서 합쳐도 될것 같다.)

<article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>

	<?php 
			echo $post->ID;
			$pts_id = get_post_meta($post->ID, 'pts_id')[0];
	?>
	<tr><td><?=$pts_id?></td><td>빈칸입니다.</td></tr>
</article><!-- #post-## -->

Untitled-1

이렇게 나온다. 저 빈칸들을 이용해 나중에 하위 레코드를 보거나, 추가적인 기능을 사용해볼 수 있겠다.

** 중요한 것은 저렇게 table로 해버리면 안된다. 예시를 위해 대강 table로 한 것이고, <article> 같은 태그가 있으니 div로 잘 쌓아서 table처럼 만들어야 할 것 같다. 아니면 article 태그를 없애버리든지?? **


다음 포스팅에서는

다음엔 codex를 이용한 검색을 만들 계획인데, 예를들면 위의 데이터를 이용해서

/patients/2016080304/ 라고 치면 바로 2016080304에 해당하는 기록들만 다시 쭉 나오게하는 방식이다.

또한 주민등록번호를 암호화시켜 저장하는 방법을 한번 알아봐야겠다.

References

  • http://www.billerickson.net/code/wp_query-arguments/
  • https://codex.wordpress.org/Post_Types