Blog

  • 2024년 건강검진 결과 업데이트

    어머니와 나 둘이 지난 6월 12일 수요일 같은 날 같은 병원에서 건강 검진을 받음. 둘다 갑상선 쪽에 뭔가 작은 혹이 발견됨.

    6월 19일 갑상선쪽 자세한 검진을 받음. 이 때 각각 조직 검사도 받음. 이 때까지만 해도 초음파 소견으로 어머니 쪽이 징후가 나빠 보이고 나는 괜찮아 보였다고 했음.

    오늘 조직 검사 결과 반전이 일어남. 모양과 다르게 내가 악성이 나오고 어머님은 이상세포만 나와서 대학 병원에서 정밀검사 재검해야 한다고.

    나는 갑상선유두암이라고 간단한 수술이 필요, 어머니는 추적관찰만 꾸준히 하라고 함.

  • 엘리멘터 프로 라이센스 불일치 알림 없애기

    엘리멘터 프로 라이센스 불일치 알림 없애기

    개발 사이트에서 원래 사이트를 복제하면, 도메인이 당연히 달라지게 된다. 그러면서 상용 라이센스 플러그인인 엘리멘터 프로 같은 플러그인은 라이센스 불일치 알림을 띄운다. 크게 사용상에 불편은 없지만 이 불일치 알림을 계속 보는 것은 성가시다.

    엘리멘터 프로의 라이센스 불일치 알림. 관리자 페이지에서 볼 수 있다.

    위에 보이는 이 그림 말이다. 이걸 안 보이게 만드는 플러그인을 따로 만들어 GIST에 올려둔다.

    https://gist.github.com/chwnam/0d43b8e919fad972a679d0537117f566

    강조한다. 이 플러그인을 결코 엘리멘터 프로의 불법복제를 장려하려고 만든 것이 아니다. 단지 개발 사이트에서 개발을 할 때 불편을 덜기 위한 임시 용도임을 명확히 한다. 단지 눈에 보이는 알림만을 보이지 않게 하는 것일 뿐이다. 만일 엘리멘터 프로가 라이센스 불일치를 감지해 기능에 제약을 걸 경우, 이 플러그인은 그런 제한을 푸는 – 소위 크랙(crack) 과 같은 행위는 절대 하지 않는다. 그러니 그냥 개발 용도라만 사용하시라. 라이센스는 별도로 걸지 않는다. 자유롭게 받아 사용하시라.

  • WASMER 이용한 워드프레스 로컬에서 구동하기

    https://wasmer.io/templates/wordpress-starter 에서 말한 WASMER를 이용해 PHP를 구동하고, 워드프레스까지 구동하는 획기적인 물건을 시험해 봤다.

    현재 실험 중인 SQLite 데이터베이스 엔진을 사용해 워드프레스를 구동하고, 실제로 약간의 버그는 있다. 뭐 돌아가는 것처럼 굴다가, 몇 번 해 보면 이내 에러를 내고 있다. 이건 나중에 차차 고쳐지겠지.

    DB에 내용이 저장된다면, WASMER 샌드박스에 관해 좀 더 알게된다면 무리없이 쓸 수 도 있을지 모르겠다. 그러나 아직은 개발환경으로 삼기에는 턱없이 무리이다. 그냥 이런 게 있다는 즐거움으로 알면 될 듯.

  • 워드프레스 커버 이미지 버그

    스튜디오 JT의 정재철 님이 제보하신 버그

    증상 재현

    • 멀티사이트, 에디터 이하의 권한으로 글 작성, 블록 에디터 편집 중 발생.
    • ‘이미지’ 블록을 선택해 ‘현재 미디어 URL’을 다음과 같은 URL로 변경한다.
      • https://images.unsplash.com/photo-1591273703337-fbede2a94c25?ixid=M3w0NzI4ODN8MHwxfHNlYXJjaHwxMnx8R3llb25nYm9rZ3VuZ3xlbnwwfHx8fDE3MTA3NDkwNDd8MA&ixlib=rb-4.0.3&w=1816&h=800&fit=crop
      • 포인트는 이미지 URL 에 쿼리 스트링으로 & 가 들어가야 한다는 것.
    • ‘커버’ 블록으로 바로 변환한다.
    • 저장하면, 저장은 되지만 프론트로 가 보면 이미지가 깨져 있다.
    • 다시 편집 화면으로 돌아오면 블록이 정상적으로 나오지 않는다.

    원인

    unfiltered_html 권한과 더불어 /wp-includes/kses.php 파일의 safecss_filter_attr() 함수에서의 style 속성 처리에서 약간의 문제가 겹쳐 일어남. 앞서 포인트에서 지적했듯 URL에 & 처럼 html entity 사용시 발생.

    우선 발생 조건을 다시 요악하면,

    1. 싱글 사이트에서 에디터의 권한 중 unfiltered_html 권한을 강제로 제외시키거나, 멀티사이트로 전환한다. Roles and Capabilities 문서에 따르면 에디터는 멀티사이트에서 unfiltered_html 권한을 가지지 않는다.
    2. set_current_user 액션 때 , 편집하는 사용자가 unfiltered_html 권한을 가지지 못하면 엄격한 kses 체크를 받도록 kses_init_filters() 함수가 동작한다.
    3. kses_init_filters() 함수 안에,
      add_filter( 'content_save_pre', 'wp_filter_post_kses' );
      라는 부분이 있다. 포스트 저장 시, kses 발동시키는 부분이다.
    4. kses 동작 중 wp_kses_attr_check() > safecss_filter_attr() 함수로 호출이 이어지고, safecss_filter_attr() 함수 안에서 문제가 일어난다.

    에디터에서 background-image: url();을 쓰는 것은 전혀 문제가 없는데, 이미지 URL에 파라미터가 붙게 되면, 가령 파라미터를 포함한 이미지 URL이 https://sample.image.com/flower.jpg?a=foo&b=bar 처럼 되어 있었다고 치자 (CDN인 경우 종종 이런 경우가 발생). 그러면 이것이 POST 전송되면서 https://sample.image.com/flower.jpg?a=foo&b=bar로 강제로 변경된다.

    그런데 safecss_filter_attr() 함수에서 HTML 태그 style 속성을 나눌 때 단순히 ‘;’ 만을 기준으로 나누게 구현되어 있다.

    function safecss_filter_attr( $css, $deprecated = '' ) {  
        if ( ! empty( $deprecated ) ) {  
           _deprecated_argument( __FUNCTION__, '2.8.1' ); // Never implemented.  
        }
        ...
        $css_array = explode( ';', trim( $css ) );Code language: PHP (php)

    그러므로 여기서 CSS 속성들이 잘못 분리된다. 그래서 background-image 속성이 손상되고, 따라서 저장 이후에는 올바르게 블록이 불러와지지 않는 문제가 발생한다. 다만 블록 자체는 해당 URL을 잘 기억하고 있어, 복구가 가능하다. 이는 블록의 속성값들이 보통 post_content 에 HTML 주석 형태로 저장되기 때문으로 주석에서는 이런 URL 필터링이 동작하기 않기 때문이다.

    해결책

    • 옵션 1: 멀티사이트에서 계정에게 unfiltered_html 권한을 특별히 부여한다.
    • 옵션 2: url() 부분에서 & 같은 게 나오지 않도록 URL을 관리한다.
    • 옵션 3: 필터를 사용해 강제로 url() 에 & 같은 것을 &로 변환한다. PHP html_entity_decode() 함수가 도움이 될 것이다.

    대충 이렇게 mu-plugin으로 구현한다.

    <?php  
    /**
     * mu-plugin 디렉토리에 resolve-url.php 로 저장.
     */
    function resolve_url_set_current_user() {  
        if ( ! current_user_can( 'unfiltered_html' ) ) {  
           add_filter( 'pre_kses', 'resolve_url_fix_url', 9 );  
        }  
    }  
    
    function resolve_url_fix_url( $data ) {  
        return preg_replace_callback( '/url\(([^)]+)\)/', 'resolve_url_replace', $data );  
    }  
    
    function resolve_url_replace( $matches ) {  
        if ( isset( $matches[1] ) ) {  
           $parsed = parse_url( $matches[1] );  
           if ( isset( $parsed['query'] ) && str_contains( $parsed['query'], ';' ) ) {  
              $decoded = html_entity_decode( $matches[1], );  
              return "url($decoded)";  
           }  
        }  
        return $matches[0];  
    }  
    
    add_action( 'set_current_user', 'resolve_url_set_current_user' );
    Code language: PHP (php)