init_classes(); $this->init(); } private function init_classes() { $this->Template = new Template(); $this->Actions = new Actions(); } private function init() { $this->init_defaults(); $this->revision = $this->default->revision; } private function init_defaults() { $this->default = new stdClass(); $this->default->revision = [ 'revisionid' => 0, 'userid' => 0, 'textareaid' => '', 'postid' => 0, 'body' => '', 'created' => 0, 'version' => 0, 'email' => '', 'url' => '', ]; $this->default->revision_format = [ 'revisionid' => '%d', 'userid' => '%d', 'textareaid' => '%s', 'postid' => '%d', 'body' => '%s', 'created' => '%d', 'version' => '%d', 'email' => '%s', 'url' => '%s', ]; $this->default->sql_select_args = [ 'include' => [], 'exclude' => [], 'userids_include' => [], 'userids_exclude' => [], 'textareaids_include' => [], 'textareaids_exclude' => [], 'postids_include' => [], 'postids_exclude' => [], 'urls_include' => [], 'urls_exclude' => [], 'emails_include' => [], 'emails_exclude' => [], 'orderby' => 'revisionid', 'order' => 'DESC', 'offset' => null, 'row_count' => null, ]; } public function get_current_url_query_vars_str() { $url_query_vars_str = wpforo_get_url_query_vars_str(); $url_query_vars_str = preg_replace( '#/?\?.*$#isu', '', $url_query_vars_str ); $wpf_url_parse = array_filter( explode( '/', trim( (string) $url_query_vars_str, '/' ) ) ); $wpf_url_parse = array_reverse( $wpf_url_parse ); if( in_array( wpforo_settings_get_slug( 'paged' ), $wpf_url_parse ) ) { foreach( $wpf_url_parse as $key => $value ) { unset( $wpf_url_parse[ $key ] ); if( $value === wpforo_settings_get_slug( 'paged' ) ) break; } $wpf_url_parse = array_values( $wpf_url_parse ); $wpf_url_parse = array_reverse( $wpf_url_parse ); $url_query_vars_str = implode( '/', $wpf_url_parse ); } if( ! $url_query_vars_str ) $url_query_vars_str = 'wpforo_home_url'; return $url_query_vars_str; } public function parse_revision( $revision ) { $revision = array_merge( $this->default->revision, (array) $revision ); if( $revision['body'] ) { $revision['body'] = preg_replace( '#[\r\n\t\s\0]*
#iu', "\r\n", (string) $revision['body'] );
$revision['body'] = wpforo_kses( trim( (string) $revision['body'] ) );
$revision['body'] = stripslashes( (string) $revision['body'] );
}
return $revision;
}
private function parse_args( $args ) {
$args = wpforo_parse_args( $args, $this->default->sql_select_args );
$args['include'] = wpforo_parse_args( $args['include'] );
$args['exclude'] = wpforo_parse_args( $args['exclude'] );
$args['userids_include'] = wpforo_parse_args( $args['userids_include'] );
$args['userids_exclude'] = wpforo_parse_args( $args['userids_exclude'] );
$args['textareaids_include'] = wpforo_parse_args( $args['textareaids_include'] );
$args['textareaids_exclude'] = wpforo_parse_args( $args['textareaids_exclude'] );
$args['postids_include'] = wpforo_parse_args( $args['postids_include'] );
$args['postids_exclude'] = wpforo_parse_args( $args['postids_exclude'] );
$args['urls_include'] = wpforo_parse_args( $args['urls_include'] );
$args['urls_exclude'] = wpforo_parse_args( $args['urls_exclude'] );
$args['emails_include'] = wpforo_parse_args( $args['emails_include'] );
$args['emails_exclude'] = wpforo_parse_args( $args['emails_exclude'] );
return $args;
}
/**
* Build prepared IN() clause for string values using $wpdb->prepare()
*
* @param string $column Column name (already escaped with backticks)
* @param array $values Array of string values
* @param bool $not Whether to use NOT IN instead of IN
*
* @return string|null Prepared SQL fragment or null if no valid values
*/
private function build_string_in_clause( $column, $values, $not = false ) {
if( ! is_array( $values ) || empty( $values ) ) {
return null;
}
// Filter out empty strings and reindex
$values = array_values( array_filter( $values, function( $v ) {
return is_string( $v ) && strlen( $v ) > 0;
} ) );
if( empty( $values ) ) {
return null;
}
$count = count( $values );
$placeholders = implode( ', ', array_fill( 0, $count, '%s' ) );
$operator = $not ? 'NOT IN' : 'IN';
return WPF()->db->prepare( "{$column} {$operator}({$placeholders})", ...$values );
}
public function build_sql_where( $args ) {
$where = '';
$args = $this->parse_args( $args );
$wheres = [];
// Integer fields - safe with wpforo_bigintval (casts to int)
if( ! empty( $args['include'] ) ) {
$wheres[] = "`revisionid` IN(" . implode( ',', array_map( 'wpforo_bigintval', $args['include'] ) ) . ")";
}
if( ! empty( $args['exclude'] ) ) {
$wheres[] = "`revisionid` NOT IN(" . implode( ',', array_map( 'wpforo_bigintval', $args['exclude'] ) ) . ")";
}
if( ! empty( $args['userids_include'] ) ) {
$wheres[] = "`userid` IN(" . implode( ',', array_map( 'wpforo_bigintval', $args['userids_include'] ) ) . ")";
}
if( ! empty( $args['userids_exclude'] ) ) {
$wheres[] = "`userid` NOT IN(" . implode( ',', array_map( 'wpforo_bigintval', $args['userids_exclude'] ) ) . ")";
}
if( ! empty( $args['postids_include'] ) ) {
$wheres[] = "`postid` IN(" . implode( ',', array_map( 'wpforo_bigintval', $args['postids_include'] ) ) . ")";
}
if( ! empty( $args['postids_exclude'] ) ) {
$wheres[] = "`postid` NOT IN(" . implode( ',', array_map( 'wpforo_bigintval', $args['postids_exclude'] ) ) . ")";
}
// String fields - use $wpdb->prepare() with placeholders for SQL injection protection
if( $clause = $this->build_string_in_clause( '`textareaid`', $args['textareaids_include'], false ) ) {
$wheres[] = $clause;
}
if( $clause = $this->build_string_in_clause( '`textareaid`', $args['textareaids_exclude'], true ) ) {
$wheres[] = $clause;
}
if( $clause = $this->build_string_in_clause( '`url`', $args['urls_include'], false ) ) {
$wheres[] = $clause;
}
if( $clause = $this->build_string_in_clause( '`url`', $args['urls_exclude'], true ) ) {
$wheres[] = $clause;
}
if( $clause = $this->build_string_in_clause( '`email`', $args['emails_include'], false ) ) {
$wheres[] = $clause;
}
if( $clause = $this->build_string_in_clause( '`email`', $args['emails_exclude'], true ) ) {
$wheres[] = $clause;
}
if( $wheres ) {
$where = " WHERE " . implode( " AND ", $wheres );
}
return $where;
}
private function build_sql_select( $args ) {
$args = $this->parse_args( $args );
$sql = "SELECT * FROM " . WPF()->tables->post_revisions;
$sql .= $this->build_sql_where( $args );
$allowed_orderby = array_keys( $this->default->revision_format );
$orderby = in_array( $args['orderby'], $allowed_orderby, true ) ? $args['orderby'] : 'revisionid';
$order = strtoupper( $args['order'] ) === 'ASC' ? 'ASC' : 'DESC';
$sql .= " ORDER BY `" . $orderby . "` " . $order;
if( $args['row_count'] ) $sql .= " LIMIT " . wpforo_bigintval( $args['offset'] ) . "," . wpforo_bigintval( $args['row_count'] );
return $sql;
}
public function add( $data ) {
if( empty( $data ) ) return false;
$revision = $this->parse_revision( $data );
unset( $revision['revisionid'] );
if( ! $revision['created'] ) $revision['created'] = time();
if( ! $revision['url'] ) $revision['url'] = $this->get_current_url_query_vars_str();
if( ! $revision['userid'] ) $revision['userid'] = WPF()->current_userid;
if( ! $revision['email'] ) $revision['email'] = WPF()->current_user_email;
if( ! $revision['textareaid'] || ! $revision['url'] || ! $revision['body'] || ! ( $revision['userid'] || $revision['email'] ) ) return false;
$revision = wpforo_array_ordered_intersect_key( $revision, $this->default->revision_format );
if( WPF()->db->insert(
WPF()->tables->post_revisions,
$revision,
wpforo_array_ordered_intersect_key( $this->default->revision_format, $revision )
) ) {
return WPF()->db->insert_id;
}
return false;
}
public function edit( $data, $where ) {
if( empty( $data ) || empty( $where ) ) return false;
if( is_numeric( $where ) ) $where = [ 'revisionid' => $where ];
$data = (array) $data;
$where = (array) $where;
$data = wpforo_array_ordered_intersect_key( $data, $this->default->revision_format );
$where = wpforo_array_ordered_intersect_key( $where, $this->default->revision_format );
if( false !== WPF()->db->update(
WPF()->tables->post_revisions,
$data,
$where,
wpforo_array_ordered_intersect_key( $this->default->revision_format, $data ),
wpforo_array_ordered_intersect_key( $this->default->revision_format, $where )
) ) {
return true;
}
return false;
}
public function delete( $where ) {
if( empty( $where ) ) return false;
if( is_numeric( $where ) ) $where = [ 'revisionid' => $where ];
$where = (array) $where;
$where = wpforo_array_ordered_intersect_key( $where, $this->default->revision_format );
if( false !== WPF()->db->delete(
WPF()->tables->post_revisions,
$where,
wpforo_array_ordered_intersect_key( $this->default->revision_format, $where )
) ) {
return true;
}
return false;
}
public function get_revision( $args ) {
if( empty( $args ) ) return false;
$revision = (array) WPF()->db->get_row( $this->build_sql_select( $args ), ARRAY_A );
if( $revision ) $revision = $this->parse_revision( $revision );
return $revision;
}
public function get_revisions( $args ) {
if( empty( $args ) ) return false;
return array_map( [ $this, 'parse_revision' ], WPF()->db->get_results( $this->build_sql_select( $args ), ARRAY_A ) );
}
/**
* @param array $args
*
* @return int
*/
public function get_count( $args ) {
$sql = "SELECT SQL_NO_CACHE COUNT(*) FROM " . WPF()->tables->post_revisions;
$sql .= $this->build_sql_where( $args );
return intval( WPF()->db->get_var( $sql ) );
}
}