[태그:] php

  • 라즈베리 파이4 온도/습도센서 홈페이지에 연결(그래프 추가)

    프린터 서버로 동작하는 라즈베리 파이에 온도, 습도를 측정하는 dht11 센서를 달았다. 센서는 1,500원인데 배송비 포함 4,000원에 구매했다. 인터넷에서 바로 사용할 수 있는 python 코드를 찾았지만 동작하지 않아 gcc로 된 코드를 사용했다. 아래 그림과 같이 구성했다.

    111에러가 홈 서버 접속 시도를 차단했다. 찾아보니 서버 내 my.cnf 파일 bind 설정을 수정해야 함을 알았다.

    워드 프레스 테마 디렉토리 안 functions.php를 보면 사용자 정의 함수를 만들고, 데이터베이스를 조회할 수 있다. functions.php 파일을 수정하기 보다, header.php를 간단하게 수정했다. 스타일 등 html을 잘 모르기 때문에 가장 간단한 정보만 표시했다. 아래는 header.php 파일이다. 마지막에 4줄 정도만 넣었다.

    <?php
    /**
     * The header for our theme
     *
     * This is the template that displays all of the <head> section and everything up until <div id="content">
     *
     * @link https://developer.wordpress.org/themes/basics/template-files/#template-partials
     *
     * @package WordPress
     * @subpackage Twenty_Seventeen
     * @since Twenty Seventeen 1.0
     * @version 1.0
     */
    
    ?><!DOCTYPE html>
    <html <?php language_attributes(); ?> class="no-js no-svg">
    <head>
    <meta charset="<?php bloginfo( 'charset' ); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="profile" href="https://gmpg.org/xfn/11">
    
    <?php wp_head(); ?>
    </head>
    
    <body <?php body_class(); ?>>
    <?php wp_body_open(); ?>
    <div id="page" class="site">
    	<a class="skip-link screen-reader-text" href="#content"><?php _e( 'Skip to content', 'twentyseventeen' ); ?></a>
    
    	<header id="masthead" class="site-header" role="banner">
    
    		<?php get_template_part( 'template-parts/header/header', 'image' ); ?>
    
    		<?php if ( has_nav_menu( 'top' ) ) : ?>
    			<div class="navigation-top">
    				<div class="wrap">
    					<?php get_template_part( 'template-parts/navigation/navigation', 'top' ); ?>
    				</div><!-- .wrap -->
    			</div><!-- .navigation-top -->
    		<?php endif; ?>
    
    	</header><!-- #masthead -->
    
    	<?php
    
    	/*
    	 * If a regular post or page, and not the front page, show the featured image.
    	 * Using get_queried_object_id() here since the $post global may not be set before a call to the_post().
    	 */
    	if ( ( is_single() || ( is_page() && ! twentyseventeen_is_frontpage() ) ) && has_post_thumbnail( get_queried_object_id() ) ) :
    		echo '<div class="single-featured-image-header">';
    		echo get_the_post_thumbnail( get_queried_object_id(), 'twentyseventeen-featured-image' );
    		echo '</div><!-- .single-featured-image-header -->';
    	endif;
    	?>
    
    
    	<div class="site-content-contain">
    		<div id="content" class="site-content">
    
    /*여기 추가*/
    <div align="center">
    <?php
    $mydb = new wpdb('????','?????','???','???');$results = $mydb->get_results("SELECT * FROM `dataTemperatureAndHumidity` ORDER BY `dataTemperatureAndHumidity`.`time` DESC limit 1");foreach($results as $result){echo "온도: "; echo $result->temperature; echo ", 습도: "; echo $result->humidity;echo ", 수집시각: ";echo $result->time;}
    ?></div>
    

    다음은 라즈베리안에서 돌아가는 gcc 파일이다. 인터넷 파일 그대로 사용했고, crobtab으로 30분에 한번 실행하도록 했다. 다음 컴파일 할 때 mysql과 wiringPi 옵션을 주어야 한다.

    /* mysql connect and query sample */
    #include <stdio.h>
    #include <stdlib.h>
    #include <mysql.h>
    #include <time.h>
    #include <unistd.h>
    #include <wiringPi.h>
    #include <stdint.h>
    #define MAXTIMINGS 83
    #define DHTPIN 0 
    int dht11_dat[5] = {0, } ;
    
    void read_dht11_dat()
    {
    	uint8_t laststate = HIGH ;
    	uint8_t counter = 0 ;
    	uint8_t j = 0, i ;
    	uint8_t flag = HIGH ;
    	uint8_t state = 0 ;
    	float f ;
    	dht11_dat[0] = dht11_dat[1] = dht11_dat[2] = dht11_dat[3] = dht11_dat[4] = 0 ;
    	pinMode(DHTPIN, OUTPUT) ;
    	digitalWrite(DHTPIN, LOW) ;
    	delay(18) ;
    	digitalWrite(DHTPIN, HIGH) ;
    	delayMicroseconds(30) ;
    	pinMode(DHTPIN, INPUT) ;
    	for (i = 0; i < MAXTIMINGS; i++) {
    		counter = 0 ;
    		while ( digitalRead(DHTPIN) == laststate) {
    			counter++ ;
    			delayMicroseconds(1) ;
    			if (counter == 200) break ;
    		}
    		laststate = digitalRead(DHTPIN) ;
    		if (counter == 200) break ; // if while breaked by timer, break for
    		if ((i >= 4) && (i % 2 == 0)) {
    			dht11_dat[j / 8] <<= 1 ;
    			if (counter > 20) dht11_dat[j / 8] |= 1 ;
    			j++ ;
    		}
    	}
    	if ((j >= 40) && (dht11_dat[4] == ((dht11_dat[0] + dht11_dat[1] + dht11_dat[2] +
    						dht11_dat[3]) & 0xff))) {
    		printf("humidity = %d.%d %% Temperature = %d.%d *C \n", dht11_dat[0],
    				dht11_dat[1], dht11_dat[2], dht11_dat[3]) ;
    	}
    	else printf("Data get failed\n") ;
    }
    
    float RandomFloat(float a, float b) {
    	//seed 값 현재 시각으로 초기화
    	srand(time(NULL));
        float random = ((float) rand()) / (float) RAND_MAX;
    
        float diff = b - a;
        float r = random * diff;
        return a + r;
    }
     
    int main(int argc, char **argv)
    {
    		if (wiringPiSetup() == -1) exit(1) ;
    		char temp[10];
    		char humidity[10];
    
    		read_dht11_dat();
    
    		sprintf(temp, "%d.%d", dht11_dat[2], dht11_dat[3]);
    		sprintf(humidity, "%d.%d",dht11_dat[0], dht11_dat[1]);
    
    		MYSQL mysql;
    		MYSQL *conn;
            MYSQL_RES *result;
            MYSQL_ROW row;
    
    		//printf("now: %d-%d-%d %d:%d:%d\n",tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,tm.tm_hour,tm.tm_min, tm.tm_sec);
     
            char query_buffer[2048];
    		conn = mysql_init(&mysql);
    
    		//float temper, centerVal;		//온도, 중심값.
    		//centerVal=25;
    		//한글을 사용하기 위해 utf-8로 설정.
    		mysql_options(conn, MYSQL_SET_CHARSET_NAME, "utf8");
    		mysql_options(conn, MYSQL_INIT_COMMAND, "SET NAMES utf8");
    		//18, 19행은 한글 사용하기 위해, mysql  옵션 수정..
    		//아래는 서버 설정에 맞도록 수정..
    		if(!mysql_real_connect(conn, "????", "????", "????", NULL, 3306, NULL, 0)){
    				fprintf(stderr,"error %s", mysql_error(conn));
    				printf("cannot connect");
    				exit(1);
    		}
    		else{
    			//아래는 test_db를 사용하도록 수정..
    				if (mysql_select_db(conn, "????")){
    						printf("cannot use databases");
    						exit(1);
    				}
    		}
    
    			time_t t =time(NULL);
    			struct tm tm = *localtime(&t);
    
    			sprintf(query_buffer, "select * from dataTemperatureAndHumidity");
    			mysql_query(conn, query_buffer);
    			result = mysql_store_result(conn);
    
    			while( (row = mysql_fetch_row(result)) != NULL){
    				printf("row[0],%s, %s, %s",row[0], row[1], row[2]);
    			}
    			sprintf(query_buffer, "INSERT INTO `dataTemperatureAndHumidity`(`time`, `temperature`, `humidity`) VALUES ('%d-%d-%d %d:%d:%d', %s, %s);",tm.tm_year+1900,tm.tm_mon+1,tm.tm_mday,tm.tm_hour,tm.tm_min, tm.tm_sec, temp, humidity);
    
    
    
    			if (mysql_query(conn, query_buffer)){
    					printf("query faild : %s\n", query_buffer);
    					exit(1);
    			}
    
    		mysql_close(conn);
     
    }

    마누라에게 자랑하니, 왜 만들었냐고 한다. 아래 그림과 같이 잘 나온다.

    (업데이트)그래프를 그릴 수도 있다.

    https://stackoverflow.com/questions/32005229/how-do-i-generate-a-graph-in-mysql-and-php-based-on-my-sql-statement-result

    jpgraph 모듈을 설치해야 한다. 아래 사이트에서 jpgraph를 다운로드 받아 적당한 web page에 넣어 준다.

    https://jpgraph.net/doc/

    header.php에 graph를 직접 넣으면 안된다. JpGraph Error: HTTP headers have already been sent 이런 에러가 난다. php가 파일로 변환 후 html이 이미지로 표시하게 한다.

    https://stackoverflow.com/questions/10487796/jpgraph-error-http-headers-have-already-been-sent

    header.php

    <?php
    /**
     * The header for our theme
     *
     * This is the template that displays all of the <head> section and everything up until <div id="content">
     *
     * @link https://developer.wordpress.org/themes/basics/template-files/#template-partials
     *
     * @package WordPress
     * @subpackage Twenty_Seventeen
     * @since Twenty Seventeen 1.0
     * @version 1.0
     */
    
    ?><!DOCTYPE html>
    <html <?php language_attributes(); ?> class="no-js no-svg">
    <head>
    <meta charset="<?php bloginfo( 'charset' ); ?>">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="profile" href="https://gmpg.org/xfn/11">
    
    <?php wp_head(); ?>
    </head>
    
    <body <?php body_class(); ?>>
    <?php wp_body_open(); ?>
    <div id="page" class="site">
    	<a class="skip-link screen-reader-text" href="#content"><?php _e( 'Skip to content', 'twentyseventeen' ); ?></a>
    
    	<header id="masthead" class="site-header" role="banner">
    
    		<?php get_template_part( 'template-parts/header/header', 'image' ); ?>
    
    		<?php if ( has_nav_menu( 'top' ) ) : ?>
    			<div class="navigation-top">
    				<div class="wrap">
    					<?php get_template_part( 'template-parts/navigation/navigation', 'top' ); ?>
    				</div><!-- .wrap -->
    			</div><!-- .navigation-top -->
    		<?php endif; ?>
    
    	</header><!-- #masthead -->
    
    	<?php
    
    	/*
    	 * If a regular post or page, and not the front page, show the featured image.
    	 * Using get_queried_object_id() here since the $post global may not be set before a call to the_post().
    	 */
    	if ( ( is_single() || ( is_page() && ! twentyseventeen_is_frontpage() ) ) && has_post_thumbnail( get_queried_object_id() ) ) :
    		echo '<div class="single-featured-image-header">';
    		echo get_the_post_thumbnail( get_queried_object_id(), 'twentyseventeen-featured-image' );
    		echo '</div><!-- .single-featured-image-header -->';
    	endif;
    	?>
    
    
    	<div class="site-content-contain">
    		<div id="content" class="site-content">
    
    <div align="center">
    <?php
    
    
    		$ydata = array();
    		$y2data = array();
    		$xdata = array();
    		$mydb = new wpdb('???','???','???','???');
    		$results = $mydb->get_results("SELECT * FROM `dataTemperatureAndHumidity` ORDER BY `dataTemperatureAndHumidity`.`time` DESC limit 30");
    		foreach($results as $result){
    			$ydata[] = $result->temperature;
    			$y2data[] = $result->humidity;
    			$xdata[] = strtotime($result->time);
    			#echo $result->time;
    		};
    		#echo gettype($xdata[0]);
    
    // Create graph instance
    require_once ('jpgraph/src/jpgraph.php');
    require_once ('jpgraph/src/jpgraph_line.php');
    require_once ('jpgraph/src/jpgraph_date.php');
    
    // Some (random) data
    #$ydata = array(11,3,8,12,5,1,9,13,5,7);
    
    // Size of the overall graph
    $width=400;
    $height=100;
    
    // Create the graph and set a scale.
    // These two calls are always required
    $graph = new Graph($width,$height);
    $graph->SetScale('datlin');
    $graph->title->Set("Temperature");
    
    $graph2 = new Graph($width,$height);
    $graph2->SetScale('datlin');
    $graph2->title->Set("Humidity");
    
    // Create the linear plot
    $lineplot=new LinePlot($ydata, $xdata);
    $lineplot2=new LinePlot($y2data, $xdata);
    
    // Add the plot to the graph
    $graph->Add($lineplot);
    $graph2->Add($lineplot2);
    
    // Display the graph
    $graph->Stroke("./temperature.jpg");
    $graph2->Stroke("./humidity.jpg");
    
    ?></div>
    <div align = "center"><img src = "./temperature.jpg"/> <img src = "./humidity.jpg" /> </div>
    

    잘 표시된다. 홈 페이지가 갈수록 괴상하게 변한다.

  • 디아블로3 캐릭터 정보 추출기

    디아블로3 캐릭터 정보 추출기

    디아블로3 : 영혼을 거두는 자 구매

    인터넷을 뒤지다보니 디아블로3가 망한 게임에서 탈출했음을 보았다. 2012년 제품 출시 당시, 최단 기간 가장 많이 팔린 패키지 게임이 디아블로3 였다. 그러나 블리자드가 불안정적인 서버 운영, 극악의 아이템 드롭율 설정, 사용자 계정 해킹에 대한 대응, 경매장 운영 미숙으로 즐기는 사용자가 급격하게 줄어들었다. 제작사가 2015년 확장팩 출시로 대대적인 수정을 했고, 그 결과가 망에서 갓게임로 등급 상승이다. 이런 내용과 최근 확장팩이 50% 내려갔음을 인터넷에서 보고 바로 결재를 했다. 내 스팀 계정에 찜 목록이 3개나 있는데 이를 사버리다니!!!!

    무한 파밍의 신세계지옥!!

    확장팩 구매후, 2주동안 미친듯이 파밍만 했다! 잠을 제대로 못자, 두통이 생기는 느낌이 있었다. 시차 적응이 안되는 느낌정도? 게임 개발 초기에 제작자가 사람의 심리를 잘 알아야 대박 게임을 만들 수 있다. 디아블로3의 단순화된 구성이 다음과 같다.
    1. 몹 사냥
    2. 1번으로 경헝치, 돈, 아이템 획득
    3. 특정 조건 만족시 캐릭터 능력 대폭 상승
    4. 다시 1번으로
    제작사가 컴퓨터 기술로 표현이 향상된 매우 단순한 루틴을 사용자에게 제공한다고 인식하면, 게임 디자이너가 능력자임이 확실하다.

    배틀넷 API by blizzard

    옛날부터 블리자드가 자사의 battle.net을 운영했다. 디아블로3를 시작하려면, 사용자가 이 서버에서 인증을 받아야 한다. 불안정인 서버 운영이 인증을 막았고, 사용자가 게임을 제대로 할 수 없었다. 이는 과거 환불 소동으로까지 확산되었다.
    사이트가 웹 개발자들에게 WOW, 스타크래프트, 디아블로 등 API를 제공한다. 원한다면 웹 개발자가 제공된 함수로 게임의 캐릭터가 어떤 옷을 입었는지, 몇마리의 몹을 삭제 했는지를 웹 브라우저에 표시할 수 있다. WOW가 나름 돈을 많이 버는 게임인지 관련 API가 다른 게임에 비해 상당히 많다. 그에 비해 디아블로3는 몇 개의 함수만 가지고 있다. 대표적으로 캐릭터 profile, item, 진행상태를 표시해주는 함수이다.

    사용자가 API를 사용하려면 블리자드 개발 사이트에 가입을 해야한다. 가입 후, 블리자드가 app, secert key를 주는데, 사용자가 정보를 조회하기 위해서 이 값들이 입력으로 들어가야 된다. 전에는 그렇지 않았는데, 변경되었다.

    git hub의 패키지된 코드 사용

    역시 인터넷을 뒤져보니, 어느 용자가 이미 관련 php를 모듈로 만들었다. 사용자가 이를 쓰기 위해서는 php의 모듈 관리자인 composer를 설치해야 한다.
    이 부분이 문제이다. 내 홈페이지가 워드프레스로 구성되어 있는데, composer가 이와 호환되지 않는다. 이를 해결하려면 별도 작업을 해야 하는데, 너무 멀리가는 듯 하여 그냥 쓰기로 했다.
    composer가 해당 실행되는 폴더에 composer.lock 등, 하위에 vendor를 설치한다. 위에서 예시가 되어있지만 브라우저에서 겁근 가능한 상대 경로를 지정해 놓으면 바로 사용할 수 있다.

    method 사용

    git hub에 있는 소스가 정말 사용하기 쉽다. 캐릭터를 뽑아 내려면 사용자가 battle tag를 함수의 인자로 보내줘야 한다. 이를 보내면 블리자드 서버가 캐릭터 id를 보내준다. 다시 이 id로 조회를 하면 세부적인 상태를 보내준다.
    battle tag가 영문자+#+숫자 형식이다. method가 battle tag를 인자로 가지면, #을 URI에 맞는 캐릭터로 변경해야 한다. 그러나 작성된 method의 이 부분이 살짝 미흡하다. #은 URI 코드로 보면 %23이다. 실재 dev.battle.net에서 조회되는 URI를 보면 #대신 %23으로 요청된다. 내 배틀 태그가 now0930#3468인데, “now0930%233468″로 변경해서 입력해야 한다.

    또한 제작자가 미쿡 사람인지라 미국 서버에서 관련 정보를 가져온다. git hub의 파일을 미국 서버 대신 한국 서버에서 정보를 가져오도록 kr로 바꿔야 한다. 언어를 안바꾸면 안되는데 파일 참조하여 ko_KR로 변경하면 된다. vendor/logansua/blizzard-api-client/src의 BlizzardClient.php 파일이 아래와 같다.
    59번 행 정도.

        /** 
         * Constructor
         *
         * @param string $apiKey    API key
         * @param string $apiSecret API Secret key
         * @param string $region    Region
         * @param string $locale    Locale
         */
        public function __construct($apiKey, $apiSecret, $region = 'kr', $locale = 'ko_kr')
        {   
            $options = [ 
                'apiKey'    => $apiKey,
                'apiSecret' => $apiSecret,
                'region'    => strtolower($region),
                'locale'    => strtolower($locale),
            ];
    
            $resolver = new OptionsResolver();
            $this->configureOptions($resolver, $options['region']);
    

    json 인코딩..

    php가 요청하면, 배틀넷이 관련 정보를 json 형식으로 보낸다.

    <?php
    // Include composer autoload file
     require_once __DIR__.'/../vendor/autoload.php';
    // Create a new Blizzard client with Blizzard API key and secret
    
     $client = new \BlizzardApi\BlizzardClient('unsemvbjg39hxwys5tfdaxakdedr5v95', 'JPCrKzrc7ySWJhyndx8Y9vPQQyXHMPBe');
    // Create a new Diablo service with configured Blizzard client
     $diablo = new \BlizzardApi\Service\Diablo($client);
    // Use API method for getting specific data
    //$response = $diablo->getItemDataById('Unique_Orb_Set_06_x1');
    // $response = $diablo->getHeroProfile('now0930#3468','62843148');
     //#이 URI 인코딩에 따르면 %23임..
     //#을 그대로 사용하면 error
     $response = $diablo->getCareerProfile('now0930%233468');
    //$response = $diablo->getArtisanData('blacksmith');
    // Accessing response status code
     $response->getStatusCode();
    // echo $response->getStatusCode();
    // Accessing response headers
     $response->getHeaders();
    // echo $response->getHeaders();
    // Show response body
    // echo $response->getBody();
    
    
     //아래부터는 JSON에서 데이터를 뽑아내는 부분..
    $jsonObj = json_decode($response->getBody());
    echo "<br><br>";
    echo $jsonObj->battleTag;echo "<br>";
    echo $jsonObj->heroes[1]->id;echo "<br>";
    echo $jsonObj->heroes[1]->name;echo "<br>";
    echo "Elite 몹 삭제 수 : ";print_r($jsonObj->heroes[1]->kills->elites);echo "<br>";
    //var_dump($jsonObj);
    
    $hero1 = $jsonObj->heroes[1]->id;
    echo "id is ";
    echo $hero1;
    //echo "$hero1";
    
    $response_hero = $diablo->getHeroProfile('now0930%233468',$hero1);
    $response_hero->getStatusCode();
    $response_hero->getHeaders();
    $jsonHero = json_decode($response_hero->getBody());
    //print_r($jsonHero);
    
    //echo $jsonHero;
    echo "<br><br>";
    echo "영웅 이름 :";
    print_r ($jsonHero->name);
    echo "<br>";
    for ($i=0; $i<06;$i++){
    	echo "Active Skills $i";
    	print_r ($jsonHero->skills->active[$i]->skill->name);
    	echo "<br>";
    	echo "Rune :";
    	print_r ($jsonHero->skills->active[$i]->rune->name);
    	echo "<br>";
    }
    
    //passive skills
    echo "passive skills";
    echo "<br>";
    for ($i=0;$i<3;$i++){
    	echo "$i";
    	print_r($jsonHero->skills->passive[$i]->skill->name);
    	echo "<br>";
    }
    
    
    //stats
    
    //echo $response_hero->getBody();
    
    
    
    ?>
    

    이 정보중에 무기나 마법에 대한 그림 위치가 있다. 개발자가 이를 뽑아내어 웹 브라우저에 그림으로 표시하면, 직관적인 사이트가 만들어 진다. 다만 그림들이 이름과 같이 배틀넷에서 제공되는데, 어디에서 받는지 모르겠다.
    간단히 하기위해서 나는 그냥 json을 인코딩했고, 필요 부분만 텍스트로 보여주었다. 나머지는 그냥 노가다이다.
    내 정보를 표시해 주는 주소는 다음과 같다.
    http://now0930.tk/diablo3/

  • WordPress로 에버노트 대신하기

    WordPress로 에버노트 대신하기

    워드 프레스 템플릿으로 에버노트 대신하기

    에버노트를 한 5년정도 잘 사용했었다. 작년에 에버노트의 내용을 백업하기 위해 database에 접근했으나, 에버노트 제작사에서 접근을 허용하지 않았다. 관련 프로그램들이 있었으나, 잘 되지 않았고, 데이터가 너무 많은지 파일을 받는데 한계가 있었다. 내가 만든 데이터인데 내가 제대로 소유를 못하고 있다고 생각하니 씁씁했다. 이번 기회에 에버노트를 떠나기로 하고, WordPress로 만든 블로그에 에버노트를 대신할 기능을 추가했다. 기능은 부족하지만, 나름 써보니 괜찮은 듯 하다. 텍스트는 어느 정도 입력, 조회, 수정이 가능했었고, 오늘 몇번의 시행착오 끝에 한개의 사진을 추가 가능하도록 했다.

    페이지로 php를 제공하는 템플릿 만들기

    워드프레스는 기본으로 php를 사용할 수 없다. 다행히? 사용자가 page에서 템플릿을 만든다면 사용할 수 있다. 작업을 조회/수정/입력하는 템플릿을 3개를 만들었다.

    작업 조회하는 php

    이 템플릿은 mysql에 접근하여 완료되지 않은 작업을 표시한다. 사용자가 작업을 추가할 경우, 그룹ID를 할당하는데, 이 그룹ID를 기준으로 작업을 표시한다. mysql의 database는 두 개를 만들었는데 하나는 작업 내용이고, 하나는 이미지 파일의 경로이다. 조회를 눌렀을 때, grpId로 그림의 경로가 있으면 이를 화면에 표시한다.

    wordpress 설치 디렉토리 중 wp-content가 내용을 담당하고 있다. 사용하는 theme의 경로로 이동한 다음 다음 3개의 파일을 만들었다.
    myJob.php, myJobInsert.php, myJobModify.php
    아래 Template Name을 원하는 내용으로 변경하고 page를 만들 때 이를 선택하면 해당 파일의 php 기능을 사용할 수 있다.

    <?php /* Template Name: myJob*/ ?>
    <?php
    get_header(); ?>
    
    <div id="main-content" class="main-content">
    
    <?php
        if ( is_front_page() && twentyfourteen_has_featured_posts() ) { 
            // Include the featured content template.
            get_template_part( 'featured-content' );
    
        }   
    ?>
    

    대략 아래와 같이 작업을 한다.
    1. 로그인이 되어 있는지 확인
    2. mysql user와 password를 시스템에서 읽어옮
    3. 데이터 베이스에 연결
    4. query를 날림..쿼리는 대략 다음과 같이 했다.

    $query="select * from
            (select * from  
            (select* from `workList` order by `id` desc, `업데이트일` desc) as target 
    group by `grpId`)
    as target2 where year(`완료일`) = '0000' order by `마감일` asc";
    

    php에서 template table을 만들 수 있으나, 셰션이 끊기면 임시 테이블도 없어진다. 귀찬고 데이터도 얼마 되지 않아 select를 중첩했다.
    5. query의 결과를 html로 표시해 주는 부분
    6. 이미지가 있으면 이미지도 같이 표시

    작업을 입력하는 php

    이 템플릿은 그룹ID를 할당하여 작업을 입력한다. 오늘 사진도 한장 입력을 할 수 있도록 수정했다. submit 버튼을 누르면 가장 마지막의 GrpId로 오늘 날자를 업데이트 날자로 하여 새로 항목을 만든다. 파일을 업로드 했다면, 파일 경로를 내용에 대한 데이터와 연결한다.

    템플릿은 위와 같은 방법을 만들었다. html에서 form을 설정하여 해당 내용을 $_POST로 데이터 베이스에 변수로 들어가도록 했다.
    1. 로그인 확인 및 데이터베이스에 연결
    2. 가장 마지막의 grpId를 확인
    3. +1을 하여 사용할 grpId로 설정
    4. 오늘 날자, 오늘 날자+14일을 확인하여 업데이트일, 목표일로 자동 설정
    5. form으로 해당하는 내용을 표시
    6. 이미지를 입력할 경우, 파일 이름과 경로를 설정
    7. 사용자가 submit 버튼을 누르면 내용과 이미지의 경로를 데이터베이스에 입력하고, 이미지를 설정한 경로에 업로드

    작업을 수정하는 php

    조회된 작업 중, 수정을 원하는 부분이 있으면 grpId를 확인해야 한다. 작업을 수정한는 페이지에서 Id를 입력하여 내용을 표시한 다음, 내가 원하는 내용으로 업데이트한다. 조회 버튼을 눌렀을 경우, 가장 나중에 작업된 내용이 표시된다.