: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @param mixed $delayedHumanBotFiltering Whether or not human/bot filtering should be applied in PHP rather than SQL.
* @param mixed $humanOnly When using delayed filtering, whether to show only humans or only bots.
* @throws wfLiveTrafficQueryException
public function buildQuery(&$delayedHumanBotFiltering, &$humanOnly) {
$filters = $this->getFilters();
$groupBy = $this->getGroupBy();
$startDate = $this->getStartDate();
$endDate = $this->getEndDate();
$limit = absint($this->getLimit());
$offset = absint($this->getOffset());
$wheres = array("h.action != 'logged:waf'", "h.action != 'scan:detectproxy'");
$wheres[] = $wpdb->prepare('h.ctime > %f', $startDate);
$wheres[] = $wpdb->prepare('h.ctime < %f', $endDate);
if ($filters instanceof wfLiveTrafficQueryFilterCollection) {
if (!wfConfig::liveTrafficEnabled()) {
$individualFilters = $filters->getFilters();
foreach ($individualFilters as $index => $f) {
if ($f->getParam() == 'jsRun' && $delayedHumanBotFiltering !== null && $humanOnly !== null) {
$humanOnly = wfUtils::truthyToBoolean($f->getValue());
if ($f->getOperator() == '!=') {
$humanOnly = !$humanOnly;
$delayedHumanBotFiltering = true;
unset($individualFilters[$index]);
$filters->setFilters($individualFilters);
$filtersSQL = $filters->toSQL();
$orderBy = 'ORDER BY h.ctime DESC';
$select = ', l.username';
if ($groupBy && $groupBy->validate()) {
$groupBySQL = "GROUP BY {$groupBy->getParam()}";
$orderBy = 'ORDER BY hitCount DESC';
$select .= ', COUNT(h.id) as hitCount, MAX(h.ctime) AS lastHit, u.user_login AS username';
if ($groupBy->getParam() == 'user_login') {
$wheres[] = 'user_login IS NOT NULL';
else if ($groupBy->getParam() == 'action') {
$wheres[] = '(statusCode = 403 OR statusCode = 503)';
$where = join(' AND ', $wheres);
$where = 'WHERE ' . $where;
if (!$limit || $limit > 1000) {
$limitSQL = $wpdb->prepare('LIMIT %d, %d', $offset, $limit);
$table_wfLogins = wfDB::networkTable('wfLogins');
SELECT h.*, u.display_name{$select} FROM {$this->getTableName()} h
LEFT JOIN {$wpdb->users} u on h.userID = u.ID
LEFT JOIN {$table_wfLogins} l on h.id = l.hitID
public function isValidParam($param) {
return array_key_exists(strtolower($param), $this->validParams);
public function getColumnFromParam($getParam) {
$getParam = strtolower($getParam);
if (array_key_exists($getParam, $this->validParams)) {
return $this->validParams[$getParam];
* @return wfLiveTrafficQueryFilterCollection
public function getFilters() {
* @param wfLiveTrafficQueryFilterCollection $filters
public function setFilters($filters) {
$this->filters = $filters;
public function getStartDate() {
* @param float|null $startDate
public function setStartDate($startDate) {
$this->startDate = $startDate;
public function getEndDate() {
* @param float|null $endDate
public function setEndDate($endDate) {
$this->endDate = $endDate;
* @return wfLiveTrafficQueryGroupBy
public function getGroupBy() {
* @param wfLiveTrafficQueryGroupBy $groupBy
public function setGroupBy($groupBy) {
$this->groupBy = $groupBy;
public function getLimit() {
public function setLimit($limit) {
public function getOffset() {
public function setOffset($offset) {
public function getTableName() {
if ($this->tableName === null) {
$this->tableName = wfDB::networkTable('wfHits');
* @param string $tableName
public function setTableName($tableName) {
$this->tableName = $tableName;
public function getWFLog() {
public function setWFLog($wfLog) {
class wfLiveTrafficQueryFilterCollection {
private $filters = array();
* wfLiveTrafficQueryFilterCollection constructor.
public function __construct($filters = array()) {
$this->filters = $filters;
public function toSQL() {
$filters = $this->getFilters();
/** @var wfLiveTrafficQueryFilter $filter */
foreach ($filters as $filter) {
$params[$filter->getParam()][] = $filter;
foreach ($params as $param => $filters) {
foreach ($filters as $filter) {
$filterSQL = $filter->toSQL();
$filtersSQL .= $filterSQL . ' OR ';
$sql .= '(' . substr($filtersSQL, 0, -4) . ') AND ';
$sql = substr($sql, 0, -5);
public function addFilter($filter) {
$this->filters[] = $filter;
public function getFilters() {
public function setFilters($filters) {
$this->filters = $filters;
class wfLiveTrafficQueryFilter {
protected $validOperators = array(
* @var wfLiveTrafficQuery
* wfLiveTrafficQueryFilter constructor.
* @param wfLiveTrafficQuery $query
* @param string $operator
public function __construct($query, $param, $operator, $value) {
$this->operator = $operator;
public function toSQL() {
$operator = $this->getOperator();
$param = $this->getQuery()->getColumnFromParam($this->getParam());
$value = $this->getValue();
$like = addcslashes($value, '_%\\');
$sql = $wpdb->prepare("$param LIKE %s", "%$like%");
$sql = $wpdb->prepare("$param LIKE %s", $value);
$sql = $wpdb->prepare("HEX($param) REGEXP %s", $value);
$sql = $wpdb->prepare("HEX($param) NOT REGEXP %s", $value);
$sql = $wpdb->prepare("$param $operator %s", $value);
public function validate() {
$valid = $this->isValidParam($this->getParam()) && $this->isValidOperator($this->getOperator());
if (defined('WP_DEBUG') && WP_DEBUG) {
throw new wfLiveTrafficQueryException("Invalid param/operator [{$this->getParam()}]/[{$this->getOperator()}] passed to " . get_class($this));
public function isValidParam($param) {
return $this->getQuery() && $this->getQuery()->isValidParam($param);
* @param string $operator
public function isValidOperator($operator) {
return in_array($operator, $this->validOperators);
public function getParam() {
public function setParam($param) {
public function getOperator() {
public function setOperator($operator) {
$this->operator = $operator;
public function getValue() {
public function setValue($value) {
* @return wfLiveTrafficQuery
public function getQuery() {
* @param wfLiveTrafficQuery $query
public function setQuery($query) {
class wfLiveTrafficQueryGroupBy {
* @var wfLiveTrafficQuery
* wfLiveTrafficQueryGroupBy constructor.
* @param wfLiveTrafficQuery $query
public function __construct($query, $param) {
* @throws wfLiveTrafficQueryException
public function validate() {
$valid = $this->isValidParam($this->getParam());
if (defined('WP_DEBUG') && WP_DEBUG) {
throw new wfLiveTrafficQueryException("Invalid param [{$this->getParam()}] passed to " . get_class($this));
public function isValidParam($param) {
return $this->getQuery() && $this->getQuery()->isValidParam($param);
* @return wfLiveTrafficQuery
public function getQuery() {
* @param wfLiveTrafficQuery $query
public function setQuery($query) {