init_filesystem( site_url() ) === false ) return false; $zip_file = wp_handle_upload( $_FILES['design-upload'], array( 'test_form' => false ) ); $zip_name = ''; $appearance_file = 'luxe-appearance.json'; if( isset( $zip_file['error'] ) ) { add_settings_error( 'luxe-custom', $_POST['option_page'], $zip_file['error'], 'error' ); } else { if( class_exists( 'ZipArchive' ) === true ) { $z = new ZipArchive(); $zopen = $z->open( $zip_file['file'], ZIPARCHIVE::CHECKCONS ); $stat_index_first = $z->statIndex(0); // index の最初 $style_ok = false; $appearance_ok = false; for ( $i = 0; $i < $z->numFiles; $i++ ) { $stat_index = $z->statIndex($i); // アーカイブの最初にディレクトリ以外のファイルが含まれてたら不正なファイル // アーカイブの最初にディレクトリが2つ以上あったら不正なファイル if( strpos( $stat_index['name'], '/' ) === false || ( $i > 0 && strpos( $stat_index['name'], $stat_index_first['name'] ) === false ) ) { add_settings_error( 'luxe-custom', $_POST['option_page'], __( 'Invalid file', 'luxeritas' ) . ': ' . $_FILES['design-upload']['name'], 'error' ); $err = true; break; } // スタイルシートが含まれてるかどうか if( $stat_index['name'] === $stat_index_first['name'] . 'style.css' ) { $style_ok = true; } // 外観カスタマイズ用 JSON ファイルが含まれてるかどうか if( $stat_index['name'] === $stat_index_first['name'] . $appearance_file ) { $appearance_ok = true; } } if( $style_ok === false ) { add_settings_error( 'luxe-custom', $_POST['option_page'], __( 'Stylesheets were not included', 'luxeritas' ) . ': ' . $_FILES['design-upload']['name'], 'error' ); $err = true; } if( $appearance_ok === false ) { add_settings_error( 'luxe-custom', $_POST['option_page'], __( 'File for customization were not included', 'luxeritas' ) . ': ' . $_FILES['design-upload']['name'], 'error' ); $err = true; } $zip_name = rtrim( $stat_index_first['name'], '/' ); $z->close(); unset( $z ); } else { // ZipArchive が使えない場合の臨時処理 // 使えるファイル名は英数 - _ $zip_name = preg_replace( '/(.+)(\.[^.]+$)/', '$1', basename( $zip_file['file'] ) ); if( preg_match( '/^[0-9a-zA-Z-_]+$/i', $zip_name ) != 0 ) { add_settings_error( 'luxe-custom', $_POST['option_page'], 'The only file names you can use are alphanumeric characters, hyphens, and underscores.', 'error' ); $err = true; } } if( $err === false ) { if( stripos( $zip_file['type'], '/zip' ) !== false || stripos( $zip_file['type'], '/x-zip' ) !== false || stripos( $zip_file['type'], '/octet-stream' ) !== false ) { $design_dir = SPATH . DSEP . 'design' . DSEP; // 同一ディレクトリ(ファイル)があるかの判定 if( file_exists( $design_dir . $zip_name ) === false ) { // 解凍 $unzip_error = unzip_file( $zip_file['file'], $design_dir ); // 解凍失敗 if( is_wp_error( $unzip_error ) ) { if( isset( $unzip_error->errors ) ) { foreach( (array)$unzip_error->errors as $value ) { foreach( (array)$value as $key => $val ) { add_settings_error( 'luxe-custom', $_POST['option_page'], 'unzip failure: ' . $val, 'error' ); } } } else { add_settings_error( 'luxe-custom', $_POST['option_page'], 'unzip failure', 'error' ); } $err = true; } } else { add_settings_error( 'luxe-custom', $_POST['option_page'], __( 'Directory with the same name already exists.', 'luxeritas' ), 'error' ); $err = true; } // NULL チェック(スタイルシートや JSON ファイルが ASCII かどうかの確認) // NULL が含まれてたら、疑わしいファイルとしてインストール中断(というか削除) if( $err === false ) { $null_check = (array)glob( $design_dir . $zip_name . '/' . '*.css' ); $null_check[] = $design_dir . $zip_name . '/' . $appearance_file; foreach( $null_check as $val ) { $css = $wp_filesystem->get_contents( $val ); if( stripos( $css, chr(0x00) ) !== false ) { add_settings_error( 'luxe-custom', $_POST['option_page'], __( 'Installation suspended because a suspicious file was found.', 'luxeritas' ), 'error' ); $err = true; $wp_filesystem->delete( $design_dir . $zip_name, true ); break; } } } } } $wp_filesystem->delete( $zip_file['file'] ); } }