.
*
*/
// Debug mode - for debug purpose only
$p2mixi_debug = false;
// ----------------------------------------------------------------------------
/**
* Register settings (2.7 compatibility)
*/
function p2mixi_admin_init () {
if ( function_exists( 'add_option_update_handler' ) ) {
add_option_update_handler( 'p2mixi', 'p2mixi_username' );
add_option_update_handler( 'p2mixi', 'p2mixi_password' );
add_option_update_handler( 'p2mixi', 'p2mixi_id' );
//added
add_option_update_handler( 'p2mixi', 'p2mixi_title_default' );
add_option_update_handler( 'p2mixi', 'p2mixi_header_default' );
add_option_update_handler( 'p2mixi', 'p2mixi_footer_default' );
add_option_update_handler( 'p2mixi', 'p2mixi_default' );
}
}
/**
* Register settings (the old way)
*/
function p2mixi_activate () {
if ( function_exists( 'add_option' ) ) {
add_option( 'p2mixi_username' );
add_option( 'p2mixi_password' );
add_option( 'p2mixi_id' );
//added
add_option( 'p2mixi_title_default' );
add_option( 'p2mixi_header_default' );
add_option( 'p2mixi_footer_default' );
add_option( 'p2mixi_default', true );
}
}
// ----------------------------------------------------------------------------
/**
* Renders the option box in the "Write Post" page in the wordpress admin.
*/
function p2mixi_render_option () {
// expects 'add_meta_box' function... wordpress 2.5 and and above.
add_meta_box( 'myplugin_sectionid', __( 'mixi投稿設定', 'p2mixi_textdomain' ),
'p2mixi_render_option_content', 'post', 'advanced' );
// add_options_page( __( 'mixi autopost settings', 'p2mixi_textdomain'), __( 'Mixi Autoposting', 'p2mixi_textdomain' ), 8, __FILE__, 'p2mixi_render_admin_option_content');
add_options_page( __( 'mixi投稿設定', 'p2mixi_textdomain'), __( 'mixi投稿設定', 'p2mixi_textdomain' ), 8, __FILE__, 'p2mixi_render_admin_option_content');
}
function p2mixi_render_admin_option_content () {
?>
/>
$value) {
if ( $key == 'p2mixi_footertext' ) {
return true;
}
}
return false;
}
/**
* Publishes the wordpress entry to mixi.
*
* @param number $postId
* @return postId
*/
function p2mixi_publish_handler ( $postId ) {
global $p2mixi_debug;
$p2mixi_username = get_option( 'p2mixi_username' );
$p2mixi_password = get_option( 'p2mixi_password' );
$p2mixi_id = get_option( 'p2mixi_id' );
$p2mixi_default = get_option( 'p2mixi_default' );
//added
$p2mixi_title_default = get_option( 'p2mixi_title_default' );
$p2mixi_header_default = get_option( 'p2mixi_header_default' );
$p2mixi_footer_default = get_option( 'p2mixi_footer_default' );
//added
$title = "";
$header = "";
$footer = "";
// If the post was published from the wordpress admin page.
if ( p2mixi_is_submitted_from_wp_admin( $_POST ) == true ) {
// verify this came from the our screen and with proper authorization,
// because publish_post can be triggered at other times
if ( !wp_verify_nonce( $_POST['p2mixi_noncename'], plugin_basename(__FILE__) )) {
return $post_id;
}
if ( $_POST['p2mixi_publishcheckbox'] == null || $_POST['p2mixi_publishcheckbox'] == 'false' ) {
return $postId;
}
$title = trim( $_POST['p2mixi_titletext'] );
$header = trim( $_POST['p2mixi_headertext'] );
$footer = trim( $_POST['p2mixi_footertext'] );
} else {
// If the post was published not from the wordpress admin page
// such as iphone application, user doesn't see the publishToMixi option.
// If that's the case, publishToMixi just follows the default configuration.
if ( $p2mixi_default == false ) {
return $postId;
}
$title = $p2mixi_title_default;
$header = $p2mixi_header_default;
$footer = $p2mixi_footer_default;
}
// Get the post detail from wordpress.
$post = get_post( $postId );
if ( $post->post_status != 'publish' || $post->post_type != 'post' ) {
return $postId;
}
// Extracting images from the post content.
$images = p2mixi_extract_jpeg_images( $post->post_content );
// Header
if ( $header != '' ) {
$header = str_replace( '%%URL%%', get_permalink( $postId ), $header );
$header = p2mixi_sanitize_html ( $header . "\r\n\r\n" );
}
// Body
$body = $post->post_content;
$movies = p2mixi_parse_movie_links( $body );
$body = p2mixi_replace_hyperlinks( $body, array( $images['urls'][0] ) );
$body = p2mixi_sanitize_html( $body );
$body .= $movies;
// Footer
if ( $footer != '' ) {
$footer = str_replace( '%%URL%%', get_permalink( $postId ), $footer );
$footer = p2mixi_sanitize_html( "\r\n\r\n" . $footer );
}
// Chop the body if it is too big.
// The max length for the mixi diary body is 10k letters.
// Actually it is 10k 'Japanese' letters (20k bytes) so it could be more
// if you use ASCII letters, but here just say 10k letters to make it safer.
//
// Not sure mb_ functions are available in any php env.
if ( function_exists( 'mb_strlen' ) && function_exists( 'mb_substr' ) ) {
$max_body_len = 10000 - mb_strlen( $header, 'utf-8' ) - mb_strlen ( $footer, 'utf-8' );
if ( $max_body_len < mb_strlen( $body )) {
$body = mb_substr( $body, 0, $max_body_len, 'utf-8' );
}
}
// content = header + body + footer
$content = $header . $body . $footer;
//added
if ( $title != '' ) {
$title = str_replace( '%%Title%%', $post->post_title, $title );
$title = p2mixi_sanitize_html( "\r\n\r\n" . $title );
}
//added ここまで
// Publish to Mixi
//deleted p2mixi_publish_to_mixi( $p2mixi_username, $p2mixi_password, $p2mixi_id, $post->post_title, $content, $images['images'] );
//added
p2mixi_publish_to_mixi( $p2mixi_username, $p2mixi_password, $p2mixi_id, $title, $content, $images['images'] );
return $postId;
}
function p2mixi_publish_to_mixi () {
global $p2mixi_debug;
// Using variable number of parameters.
$args = func_get_args();
$username = $args[0];
$password = $args[1];
$id = $args[2];
$title = $args[3];
$content = $args[4];
if ( func_num_args() == 6 )
{
$images = $args[5];
}
// WSSE Authentication
$nonce = "";
if ( function_exists( 'posix_getpid' ) ) {
$nonce = pack('H*', sha1(md5(time().rand().posix_getpid())));
} else {
// Use uniqid() in case of windows.
$nonce = pack('H*', sha1(md5(time().rand().uniqid())));
}
$created = date('Y-m-d\TH:i:s\Z');
$digest = base64_encode(pack('H*', sha1($nonce . $created . $password)));
$wsse_text = 'UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"';
$wsse_header = sprintf($wsse_text, $username, $digest, base64_encode($nonce), $created);
// mixi POST URL
$url = 'http://mixi.jp/atom/diary/member_id=' . $id;
$request_headers = array();
$request_headers['X-WSSE'] = $wsse_header;
$request_headers['Accept'] = '*/*';
$request_headers["Connection"] = "Close";
//------------------------------------------------------------
// Post Image
//------------------------------------------------------------
if ( $p2mixi_debug ) error_log ( "p2mixi_publish_to_mixi: # of images : " . sizeof( $images ) );
if ( sizeof( $images ) > 0 )
{
if ( $p2mixi_debug ) error_log ( "p2mixi_publish_to_mixi: Uploading images to Mixi." );
$response_headers = array();
$response_body = '';
$request_headers['Content-Type'] = 'image/jpeg';
p2mixi_http_post( $url, $request_headers, $images[0], $response_headers, $response_body );
$location = $response_headers['Location'];
if ( $p2mixi_debug ) error_log ( "p2mixi_publish_to_mixi: Finished uploading images to Mixi." );
if ( $p2mixi_debug ) error_log ( "p2mixi_publish_to_mixi: Location: $location" );
if ( $location != '' )
{
$url = $location;
}
}
//------------------------------------------------------------
// Post Text
//------------------------------------------------------------
$request_body = ""
. ""
. "$title"
. "$content"
. "";
$request_headers['Content-Type'] = 'application/atom+xml';
if ( $p2mixi_debug ) error_log ( "p2mixi_publish_to_mixi: Uploading text to Mixi." );
p2mixi_http_post( $url, $request_headers, $request_body, $response_headers, $response_body );
if ( $p2mixi_debug ) error_log ( "p2mixi_publish_to_mixi: Finished uploading text to Mixi." );
}
// ----------------------------------------------------------------------------
// Register actions to wordpress.
if ( function_exists( 'add_action' ) ) {
add_action( 'admin_init', 'p2mixi_admin_init' );
add_action( 'admin_menu', 'p2mixi_render_option' );
// add_action( 'publish_post', 'p2mixi_publish_handler' );
add_action( 'draft_to_publish', 'p2mixi_publish_handler' );
add_action( 'private_to_publish', 'p2mixi_publish_handler' );
add_action( 'pending_to_publish', 'p2mixi_publish_handler' );
add_action( 'future_to_publish', 'p2mixi_publish_handler' );
add_action( 'new_to_publish', 'p2mixi_publish_handler' );
}
if ( function_exists( 'register_activation_hook' ) ) {
register_activation_hook( __FILE__, 'p2mixi_activate' );
}
// ----------------------------------------------------------------------------
/**
* Extract the URL info from tags and
tags in the post content
* to keep the link information since all HTML tags will be stripped before submitting to mixi.
* For example, The following string 'mixi'
* will be replaced like 'mixi (http://mixi.jp)'.
* TODO: It should be able to handle more complex links.
* The logic can handle only simple tags now.
*/
function p2mixi_replace_hyperlinks_callback_a_tag ( $m ) {
// It's better to check if the URL is in $excludes here
// but I couldn't find a way to refer to the $excludes variable
// from inside this callback.
// Hence the cleanup code afterwards.
return $m[2] == $m[3] ? $m[2] : "$m[3]($m[2])";
}
function p2mixi_replace_hyperlinks_callback_img_tag ( $m ) {
return $m[2];
}
function p2mixi_replace_hyperlinks ( $text, $excludes = array() ) {
if ( $excludes == NULL ) $excludes = array();
// First process
tags to process nested cases properly
// i.e.
$text = preg_replace_callback(
'/
/i',
'p2mixi_replace_hyperlinks_callback_img_tag',
$text);
// Now the tags
$text = preg_replace_callback(
'/]*>([^<]*)<\/a>/i',
'p2mixi_replace_hyperlinks_callback_a_tag',
$text);
// Remove $excludes
foreach ( $excludes as $url ) {
$url_re = str_replace( '/', '\/', $url );
$url_re = str_replace( '?', '\?', $url_re );
$text = preg_replace(
"/(\($url_re\)|$url_re)/i",
'',
$text);
}
return $text;
}
/**
* Sanitize body text
* - Strip html tags
* - Encode any special HTML characters to properly handle html entities
*/
function p2mixi_sanitize_html ( $text ) {
$ret = $text;
$ret = preg_replace(
array(
// Remove invisible content
'@]*?>.*?@siu',
'@@siu',
'@@siu',
'@@siu',
'@@siu',
'@@siu',
'@]*?.*?@siu',
'@@siu',
'@]*?.*?@siu',
// Add line breaks before and after blocks
'@?((address)|(blockquote)|(center)|(del))@iu',
'@?((div)|(h[1-9])|(ins)|(isindex)|(p)|(pre))@iu',
'@?((dir)|(dl)|(dt)|(dd)|(li)|(menu)|(ol)|(ul))@iu',
'@?((table)|(th)|(td)|(caption))@iu',
'@?((form)|(button)|(fieldset)|(legend)|(input))@iu',
'@?((label)|(select)|(optgroup)|(option)|(textarea))@iu',
'@?((frameset)|(frame)|(iframe))@iu',
// convert br to line break
'@
@i',
),
array(
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
"\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0", "\n\$0",
"\n\$0",
"\n",
),
$ret );
$ret = strip_tags( $ret );
// -> etc.
$ret = htmlspecialchars( $ret, ENT_QUOTES, "utf-8" );
return $ret;
}
function p2mixi_parse_movie_links ( $text ) {
$ret = '';
//$ids = preg_grep( "/http:\/\/www\.youtube\.com\/watch\?v\=([0-9A-Za-z]*)/", array( $text ) );
$ids = array();
preg_match_all( "/href=\"http:\/\/www\.youtube\.com\/watch\?v=([0-9A-Za-z_]*)/", $text, $ids, PREG_PATTERN_ORDER );
foreach( $ids[1] as $id ) {
$ret .= '<externalvideo src="YT:' . $id . '">';
}
$ids = array();
preg_match_all( "/src=\"http:\/\/www\.youtube\.com\/v\/([0-9A-Za-z_]*)/", $text, $ids, PREG_PATTERN_ORDER );
foreach( $ids[1] as $id ) {
$ret .= '<externalvideo src="YT:' . $id . '">';
}
$ids = array();
preg_match_all( "/href=\"http:\/\/www\.nicovideo\.jp\/watch\/(sm[0-9]*)/", $text, $ids, PREG_PATTERN_ORDER );
foreach( $ids[1] as $id ) {
$ret .= '<externalvideo src="NC:' . $id . '">';
}
return $ret;
}
// ----------------------------------------------------------------------------
function p2mixi_extract_jpeg_images ( $html, $max = 1 ) {
global $p2mixi_debug;
$cnt = 0;
$images = array();
$urls = array();
// Matching all img tags
preg_match_all( "/(
]*>)/i", $html, $matches, PREG_SET_ORDER );
for ( $i = 0; $i < count( $matches ); $i++ ) {
if ( $p2mixi_debug ) error_log ( "p2mixi_extract_jpeg_images: >>>$matches[$i][1]<<<" );
// Download the image from the url
preg_match( "/src=\"([^\"]+)\"/i", $matches[$i][1], $url );
if ( $p2mixi_debug ) error_log ( "p2mixi_extract_jpeg_images: >>>$url[1]<<<" );
$request_headers['Accept'] = '*/*';
$request_headers["Connection"] = "Keep-Alive";
$response_headers = array();
$response_body = '';
p2mixi_http_get( $url[1], $request_headers, $response_headers, $response_body );
// Checking the data is really the jpeg data or not
// by checking 'JFIF' string inside.
// http://en.wikipedia.org/wiki/JFIF
//
// Usually the string comes up in the 7th - 11th byte
// of the data, but it does not if the image contains exif data
// because the exif headers comes before the JFIF appearance.
// Ideally, the logic should understand the exif structures.
if ( strpos( $response_body, 'JFIF' ) != false ) {
array_push( $images, $response_body );
array_push( $urls, $url[1] );
if ( ++$cnt == $max ) {
break;
}
}
}
return array( 'urls' => $urls, 'images' => $images );
}
function p2mixi_http_get ( $url, $request_headers, &$response_headers, &$response_body, $retries = 0 ) {
global $p2mixi_debug;
$url_comps = parse_url( $url );
if ( ! isset( $url_comps['port'] ) ) $url_comps['port'] = 80;
$sock = new p2mixi_TinyHttpSocket( $url_comps['host'], $url_comps['port'] );
$sock->setDebugMode( $p2mixi_debug );
if ( !$sock->connect() ) {
error_log( "p2mixi_http_get: fsockopen failed: $errstr ( $errno )" );
} else {
$request_headers["Host"] = $url_comps['host'];
$sock->send( "GET", $url, $request_headers );
$sock->recv( $response_headers, $response_body );
if ( $p2mixi_debug ) error_log( "p2mixi_TinyHttpClient.get: socket recv end " );
if ( $response_headers["Status-Code"] == 403 && $p2mixi_debug ) error_log( "p2mixi_http_get: Body: $response_body " );
// Redirection support
if ( isset( $response_headers["Status-Code"] ) ) {
$code = $response_headers["Status-Code"];
switch( $code ) {
case ( (300 <= $code && $code <= 303) || $code == 307 ):
if ( isset( $response_headers["Location"] ) ) {
$location = $response_headers["Location"];
if ( $p2mixi_debug ) error_log( "p2mixi_http_get: Redirecting($retries retries so far): $location" );
// if ( isset( $response_headers['cookies'] ) ) {
// if ( $p2mixi_debug ) error_log( "p2mixi_http_get: Setting cookies :". p2mixi_constrcut_cookies_string( $response_headers['cookies'] ) );
// $request_headers['Cookie'] = p2mixi_construct_cookies_string( $response_headers['cookies'] );
// }
p2mixi_http_get( $location, $request_headers, $response_headers, $response_body, $retries + 1 );
}
break;
}
}
}
}
function p2mixi_http_post ( $url, $request_headers, $request_body, &$response_headers, &$response_body ) {
global $p2mixi_debug;
$url_comps = parse_url( $url );
if ( ! isset( $url_comps['port'] ) ) $url_comps['port'] = 80;
$sock = new p2mixi_TinyHttpSocket( $url_comps['host'], $url_comps['port'] );
$sock->setDebugMode( $p2mixi_debug );
if ( !$sock->connect() ) {
error_log( "p2mixi_http_post: fsockopen failed: $errstr ( $errno )" );
} else {
$request_headers["Host"] = $url_comps['host'];
$request_headers['Content-Length'] = strlen( $request_body );
$sock->send( "POST", $url, $request_headers, $request_body );
$sock->recv( $response_headers, $response_body );
if ( $p2mixi_debug ) error_log( "p2mixi_http_post: socket recv end " );
}
}
function p2mixi_construct_cookies_string ( $cookies ) {
$str = "";
foreach ( $cookies as $name=>$value ) {
$str .= "$name=$value;";
}
return $str;
}
// ----------------------------------------------------------------------------
/**
* Http socket class who knows how to send and receive http headers and body.
* Copyright (c) 2001, 2002 by Martin Tsachev. All rights reserved.
* mailto:martin@f2o.org
* http://martin.f2o.org
*
* Redistribution and use in source and binary forms,
* with or without modification, are permitted provided
* that the conditions available at
* http://www.opensource.org/licenses/bsd-license.html
* are met.
*/
class p2mixi_TinyHttpSocket {
var $fp = null;
var $host;
var $port;
var $getlen = 1024;
var $timeout = 30;
var $debug = false;
var $request;
var $connection;
/**
* constructor
*/
function p2mixi_TinyHttpSocket ( $host, $port ) {
$this->host = $host;
$this->port = $port;
}
function setDebugMode ( $debug ) {
$this->debug = $debug;
}
function connect ( ) {
if ( $this->fp ) {
return true;
}
$this->fp = @fsockopen( $this->host, $this->port, $errno, $errstr, $this->timeout );
if ( !$this->fp ) {
return false;
}
return true;
}
function close ( ) {
fclose( $this->fp );
}
function constructHeaderString ( $headers ) {
$str = "";
foreach ( $headers as $name=>$value ) {
$str .= "$name: $value\r\n";
}
return $str;
}
// function parseCookie ( $line ) {
// // $line should look like following
// // name=value; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT
// // Get the "Set-Cookie: name=value" part
// $cookie = explode( ";", $line );
// // Split name and value.
// $cookie = explode ( "=", $cookie[0] );
// if ( count( $cookie ) == 2 ) {
// return array ( 'name' => trim( $cookie[0] ), 'value' => trim( $cookie[1] ) );
// }
// else {
// return array ();
// }
// }
function send ( $method, $url, $headers, $body='' ) {
$out = "$method $url HTTP/1.1\r\n";
$out .= $this->constructHeaderString( $headers );
$out .= "\r\n";
if ( $body != '' ) {
$out .= $body;
}
$this->request = $out;
if ( isset( $headers["Connection"] ) ) {
$this->connection = strtolower( $headers["Connection"] );
}
if ( $this->fp ) {
if ( $this->debug ) error_log( "p2mixi_TinyHttpSocket.send: $out " );
fwrite( $this->fp, $out );
}
}
function recv ( &$headers, &$body ) {
$headers = array();
$header = fgets( $this->fp, $this->getlen );
if ( !$header ) { // if disconnected since send
$this->connect();
fputs( $this->fp, $this->request );
$header = fgets( $this->fp, $this->getlen );
}
preg_match( '|^HTTP.+ (.+) |', $header, $matches );
$headers["Status-Line"] = trim( $header );
$headers["Status-Code"] = intval( $matches[1] );
if ( $this->debug ) error_log( "p2mixi_TinyHttpSocket.recv: Status line: ".$header );
if ( $header == "" ) return;
$mime = '';
$transfer = '';
$connection = $this->connection;
// $cookies = array();
while ( $line = fgets( $this->fp, $this->getlen ) ) {
if ( $line == "\r\n" ) { break; }
$param = explode( ":", $line, 2 );
$name = trim( $param[0] );
$value = trim( $param[1] );
$headers[$name] = $value;
if ( $this->debug ) error_log( "p2mixi_TinyHttpSocket.recv: $name = $value" );
switch( $name ) {
case 'Content-Length':
$length = intval( $value );
break;
case 'Content-Type':
$mime = strtolower( $value );
break;
case 'Connection':
$connection = strtolower( $value );
break;
case 'Transfer-Encoding':
$transfer = strtolower( $value );
break;
// case 'Set-Cookie':
// $cookie = $this->parseCookie( $value );
// if ( count( $cookie ) > 0 ) {
// $cookies[$cookie['name']] = $cookie['value'];
// }
// break;
}
}
// if ( count( $cookies ) > 0 ) {
// $headers['cookies'] = $cookies;
// }
$body = '';
if ( $connection == 'close' ) {
if ( $this->debug ) error_log( "p2mixi_TinyHttpSocket.recv: looping for closed connection" );
while ( !feof( $this->fp ) ) {
$body .= fread( $this->fp, $this->getlen );
}
return ;
}
if ( isset( $length ) and strpos( $transfer, 'chunked' ) === false) {
if ( $this->debug ) error_log( "p2mixi_TinyHttpSocket.recv: looping unchunked keep-alive connection for $length" );
while ( true ) {
if ( $length <= 0 ) { break; }
$read = fread( $this->fp, $length );
$length -= strlen( $read );
$body .= $read;
}
return ;
}
// chunked encoding
$length = fgets( $this->fp, $this->getlen );
$length = hexdec( $length );
if ( $this->debug ) error_log( "p2mixi_TinyHttpSocket.recv: looping chunked keep-alive connection for $length" );
while ( true ) {
if ( $length == 0 ) { break; }
$body .= fread( $this->fp, $length );
fgets( $this->fp, $this->getlen );
$length = fgets( $this->fp, $this->getlen );
$length = hexdec( $length );
}
fgets( $this->fp, $this->getlen );
return;
}
}