Blocked ip's from iptables to mysql - php

Dealing with iptables and php / mysql but no luck, I'm trying to find an solution to add blocked ip's ( yes, more than one at once ) from iptables to mysql. Is anyone able to help with this issue?
<?php
$hostname = gethostname();
$name = permanent;
require_once("/etc/blocked/inc/config.inc.php");
$output = shell_exec('iptables -S permanent');
$lines=explode("\n",$output);
$fail=array();
$r="/(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/";
foreach($lines as $line){
$t=array();
preg_match($r,$line,$t);
$ip=$t[0];
$fail[0]=$ip;
if ($fail[0] == '') {
}
else {
#echo "$hostname,$fail[0],$name \n";
$query = "INSERT INTO blockedips (hostname,ip,name) VALUES ('$hostname','$fail[0]','$name')" ;
$result = mysqli_query($link,$query) or die('Query failed: ' . mysqli_error($link));
mysqli_close($link);
exit;
}
}
?>

Alright, I've got some time to kill. I suggest you read up on how to use preg_match(), as well as reconsider how you're treating your database connection. I also corrected a bunch of other small mistakes and needless code.
<?php
$hostname = gethostname();
// this needs to be quoted
$name = "permanent";
require_once("/etc/blocked/inc/config.inc.php");
// specify the full path to your binary
$output = exec("/sbin/iptables -S permanent", $lines);
// exec will create an array
//$lines=explode("\n",$output);
// you weren't capturing the IP address here
$r="/((?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))/";
foreach($lines as $line){
// this can create itself
// $t=array();
// why aren't you checking the results of this call?
if (preg_match($r, $line, $t)) {
// $t[0] is the whole string, $t[1] is the first match
$ip = $t[1];
// I don't know why you were re-assigning this to another array
// $fail[0]=$ip;
#echo "$hostname,$ip,$name \n";
$query = "INSERT INTO blockedips (hostname,ip,name) VALUES ('$hostname','$ip','$name')";
$result = mysqli_query($link,$query)
or die('Query failed: ' . mysqli_error($link));
// why close your database? your second query isn't going to work too well
// mysqli_close($link);
// oh, will never be a second value. is this intentional? why have a loop then?
// exit;
}
}
?>
But wait! Prepared statements are made to be prepared once and executed repeatedly, while reducing system overhead. I'd also strongly suggest migrating to PDO, or at least use the mysqli object-oriented interface.
<?php
$hostname = gethostname();
$name = "permanent";
require_once("/etc/blocked/inc/config.inc.php");
$output = exec("/sbin/iptables -S $name", $lines);
$stmt = $link->prepare("INSERT INTO blockedips (hostname,ip,name) VALUES (?, ?, ?)";
$octet = "(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)";
$ip = "$octet\.$octet\.$octet\.$octet";
foreach($lines as $line){
if (preg_match("/($ip)/", $line, $t)) {
$ip = $t[1];
$stmt->bind_param("sss", $hostname, $ip, $name);
if ($stmt->execute() === false) {
echo 'Query failed: ' . $link->error();
$link->close();
exit;
}
}
}
?>

Related

PHP page output/echo always null, no generated error logs

I'm trying to create an extremely basic script that can function as a REST API. I've been having a lot of trouble getting any output to show on the page. In the code below you can see a couple of the commented methods I've tried to get an output. If I remove the printf while loop and just use the responseData = json_encode($result) line, I get a JSON output in the proper format but only containing null values. (Table columns have the appropriately named table headers but nothing else, no data is returned). For the record, the SQL statements, are being properly executed without error. The below script generates no PHP.log errors when run. If I change the SQL to an insert statement I can see the resulting values in the database. So whatever is going on here is some issue with simply outputting those values to the page.
This is the code for the entire page script I am using;
<?php
define("PROJECT_ROOT_PATH", __DIR__);
define("DB_HOST", "localhost");
define("DB_USERNAME", "testuser");
define("DB_PASSWORD", "testpw");
define("DB_DATABASE", "testgb");
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$uri = explode( '/', $uri );
/** Basic Input Filter **/
function input_filter($data) {
$data= trim($data);
$data= stripslashes($data);
$data= htmlspecialchars($data);
return $data;
}
/**
* Get URI elements.
*
* #return array
*/
function getUriSegments()
{
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$uri = explode( '/', $uri );
return $uri;
}
function sendOutput($data, $httpHeaders=array())
{
header_remove('Set-Cookie');
if (is_array($httpHeaders) && count($httpHeaders)) {
foreach ($httpHeaders as $httpHeader) {
header($httpHeader);
}
}
echo $data;
exit;
}
/**
* "/[usertoken]/read" Endpoint - retrieve orders from db
*/
function readAction()
{
$strErrorDesc = '';
$requestMethod = $_SERVER["REQUEST_METHOD"];
$arrQueryStringParams = parse_str($_SERVER['QUERY_STRING'], $query);
if (strtoupper($requestMethod) == 'GET') {
try {
$intLimit = 100;
if (isset($arrQueryStringParams['limit']) && $arrQueryStringParams['limit']) {
$intLimit = $arrQueryStringParams['limit'];
}
$intItemId = 0;
if (isset($arrQueryStringParams['itemid']) && $arrQueryStringParams['itemid']) {
$intItemId = $arrQueryStringParams['itemid'];
echo $intItemId;
}
$conn = mysqli_connect(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_DATABASE);
if ($conn->connect_error)
{
die("Connection failed: ". mysqli_connect_error());
}
$sql = "SELECT * FROM verified_orders WHERE itemid=?;";
$stmt = mysqli_stmt_init($conn);
if (!mysqli_stmt_prepare($stmt, $sql)) {
die("Statement preparation failed.");
} else {
mysqli_stmt_bind_param($stmt, "d", $intItemId);
mysqli_stmt_execute($stmt);
$result = mysqli_stmt_get_result($stmt);
if ($row = mysqli_fetch_assoc($result)) {
while ($row = $result -> fetch_row()) {
printf ("%s (%s)\n", $row[0], $row[1]);
}
}
/*$responseData = json_encode($result);*/
}
} catch (Error $e) {
$strErrorDesc = $e->getMessage().'.';
$strErrorHeader = 'HTTP/1.1 500 Internal Server Error';
}
} else {
$strErrorDesc = 'Method not supported';
$strErrorHeader = 'HTTP/1.1 422 Unprocessable Entity';
}
// send output
if (!$strErrorDesc) {
/*echo $responseData;
} else {
echo $responseData;*/
}
}
if (isset($uri[2]) && $uri[2] != 'user') {
header("HTTP/1.1 404 Not Found");
exit();
}
if ($uri[3] == "read") {
readAction();
}
?>
Database API changes and misleading parse_str()
updated: There were a few errors going on in the end, combined with a lack of logs, resulting in a messy thread; I've updated this answer postmortem, to consolidate the solutions and realizations.
There seemed to be some problems with the database access (mixed forms of mysqli-fetching) and potentially false expectations, due to associative vs numeric results ($row[0], $row[1] were attempted in assoc mode). In the end, the entire set of Mysqli connect/prepare/query/fetch-calls were replaced with known good PDO variants; namely:
if (!($conn = new PDO(sprintf('mysql:dbname=%s;host=%s', DB_DATABASE, DB_HOST), DB_USERNAME, DB_PASSWORD, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ])))
throw new Exception('Connection failed');
if (!($stmt = $conn->prepare('
SELECT *
FROM verified_orders
WHERE itemid = :itemid
ORDER BY itemid
'))) throw new Exception('Prepare failed');
if (!$stmt->execute([ 'itemid' => $intItemId ]))
throw new Exception('Execute failed');
if (!($data = $stmt->fetchAll( PDO::FETCH_ASSOC|PDO::FETCH_GROUP|PDO::FETCH_UNIQUE )))
throw new Exception('Fetch failed');
Which is not to say that the mysqli-variants itself couldn't have been fixed. The problem just wasn't readily apparent.
The PDO database calls solved most problems, but not the absence of any value in the $intItemId variable (which is used in the SELECT query). That variable lived downstream from $arrQueryStringParams, which in turn was ment to be set here:
$arrQueryStringParams = parse_str($_SERVER['QUERY_STRING'], $query);
At first glance this looked fine, however the parse_str() function produces no return value. It actually injects the results into the 2nd argument, which in this case was a stray variable called $query (which wasn't used anywhere else at all).
The proper syntax for parse_str() would be:
parse_str($_SERVER['QUERY_STRING'], $arrQueryStringParams);
Original attempts at a solution
You're using mysqli_fetch_assoc to fetch the query results (note the associative).
This means the results won't end up in $row[0], $row[1], ... But instead $row is an associative array based on the column names, such as $row['itemid'].
offtopic note: you should remove the ; at the end of your SQL query. It can be a part of a SQL script command , where it denotes the end of a statement, but it isn't considered part of a single query.
update
Try replacing
$result = mysqli_stmt_get_result($stmt);
if ($row = mysqli_fetch_assoc($result)) {
while ($row = $result -> fetch_row()) {
printf ("%s (%s)\n", $row[0], $row[1]);
}
}
with
while ($row = $result->fetch_array(MYSQLI_BOTH)) {
printf ("%s (%s)\n", $row[0], $row[1]);
}
See if that fixes the problem.
if it does not then check the logfiles and show the output of var_dump($x) for $row, $result, $stmt and $conn.
And then repeat that process again after replacing the SQL with:
$sql = "SELECT 123 AS num, 'abc' AS str, ? AS inputval";
update 2
Weird results, without anything to go on debugging wise, its probably best to try the following. (Temporarily) remove all your code starting at the line:
/** Basic Input Filter **/
and from there, all the way to the end of the file. Basically only leaving your defines; and then copy/paste the following at the bottom of the file, and then try to visit the page in your webbrowser, see what it prints.
try {
echo 'A';
if (!($conn = new PDO(sprintf('mysql:dbname=%s;host=%s', DB_DATABASE, DB_HOST), DB_USERNAME, DB_PASSWORD, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ])))
throw new Exception('Connection failed');
echo 'B';
if (!($stmt = $conn->prepare('
SELECT *
FROM verified_orders
WHERE itemid = :itemid
OR 1=1
ORDER BY itemid
LIMIT 20
'))) throw new Exception('Prepare failed');
echo 'C';
if (!$stmt->execute([ 'itemid' => 1 ]))
throw new Exception('Execute failed');
echo 'D';
if (!($data = $stmt->fetchAll( PDO::FETCH_ASSOC|PDO::FETCH_GROUP|PDO::FETCH_UNIQUE )))
throw new Exception('Fetch failed');
echo 'E';
echo PHP_EOL . '<br>';
var_dump( $data );
echo PHP_EOL . '<br>';
echo 'F';
} catch (Throwable $e) { echo PHP_EOL . '<br>Exception: ' . htmlentities($e->getMessage()); }
Exit(0);

PHP > Invalid Argument supplied for foreach()

In short, I am trying to figure out what is wrong with my foreach statement. I have been trying to work on finding the error for over a day know and I'm running out of time. This program is supposed to parse a json array and post it up to a mysqli database.
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
$a = print_r(var_dump($GLOBALS),1);
echo htmlspecialchars($a);
$servername = "#";
$username = "#";
$password = "#";
$dbname = "#";
// Create connection
$conn = mysqli_connect($servername, $username, $password, $dbname);
echo "Connection Successful : ";
// Check connection
if (!$conn) {
die("Connection failed: " . mysqli_connect_error());
}
// Read JSON file
$jsondata = file_get_contents('scripts/AUDIT_DIR/report.json');
echo "JSON File Read : ";
// Convert and Loop
$item = json_decode($jsondata, true);
echo "JSON File Decoded : ";
foreach($item as $arr)
{
$id = $arr["id"];
$hostname = $arr["hostname"];
$ip = $arr["ip"];
$package = $arr["package"];
$publisher = $arr["publisher"];
$origin = $arr["origin"];
$version = $arr["version"];
$size = $arr["size"];
$sql = "INSERT INTO testtable(id, hostname, ip, package, publisher, origin, version, size)
VALUES ('10', '$hostname', '$ip', '$package', '$publisher', '$origin', '$version', '$size')";
if (mysqli_query($conn, $sql))
{
echo "New record created successfully : ";
}
else
{
echo "Error: " . $sql . "<br>" . mysqli_error($conn);
}
}
?>
You likely have an invalid return from your json_decode() you can check this with a var_dump($item); after your json_decode()
In php json_decode() will return NULL if the json cannot be decoded or if the encoded data is deeper than the recursion limit. http://php.net/manual/en/function.json-decode.php
You need to properly guard for such a case that $item === null and not assume you will always get a valid return for your foreach() params.
Example showing your error happens when $item = null
https://3v4l.org/oNr8P

Mysqli num rows not working

I have a fairly basic script (i'm used to mysql but i'm moving to mysqli)
<?php
include("../includes/functions.php");
/////////////////////////////////////////////////////////////////////////
$debugMode = 1;
/////////////////////////////////////////////////////////////////////////
if (isset($_GET['u']))
{
// database connection
$c = mysqli_connect("localhost", "xxx", "xxx", "xxx");
// initial query to check if the domain is already in the database
$q = $c->query("SELECT * FROM `domains` WHERE `domain_name`='".trim($s[0])."'");
$v = $q->fetch_assoc();
$r = $q->num_rows;
// check if the string exists in the database
if ($r > 0)
{
// do not enter if greater than 0
} else {
// vars
$u = $_GET['u'];
// DEBUG
if ($debugMode)
{
$fp = fopen('u.txt', 'a');
fwrite($fp, "$u" . "\n");
fclose($fp);
}
// do a split of "|"
$s = explode("|", $u);
// check alexa rank and update
$alexa = alexa_rank($s[0]);
// check connection
if (mysqli_connect_errno())
{
echo mysqli_connect_error();
} else {
// insert query if there is no errors
$i = $c->query("INSERT INTO `domains` (`domain_id`,`domain_name`,`domain_pr`,`domain_alexa_rank`,`domain_moz_da`,`domain_moz_pa`,`domain_date`) VALUES ('','".$s[0]."','".$s[1]."','".$alexa."','".$s[2]."','".$s[3]."',NOW())");
}
}
} else {
header("Location: http://www.site.info/");
}
?>
It looks fairly simple, the problem is the count part isn't working, it's still adding to the database duplicate entries, i also tried:
mysqli_num_rows($q);
This still doesn't seem to work, am i missing something simple?
thanks guys
You should first be sure your query is right.
So please debug your code like that;
$SQL = "SELECT * FROM `domains` WHERE domain_name`='".trim($s[0])."'";
echo "My Query: ". $SQL;
$q = $c->query($SQL);
I guess you have problem on your $s variable. If your sql query is right you can check $v variable have any record if $v variable is an array and have value you have more than one record and you can pass to insert statements if not you can add.
ahh thank you! i found my top query was failing because i was using the explode further down the code! thanks guys.

Why isn't this sending to my mysql server?

So, everytime I go to http://localhost/api/calls.php?gamename=test&gameowner=hi&gameownerid=1&placeid=2&serverjobid=hi&serverid=jaja&serverplayers=1&sendername=bob&senderid=3&senderage=14&senderwarnings=0&calltype=non&reportinfo=hi&suspect=none
it shows absolutely nothing and doesn't send the data to my mysql database.
Here is my code. I removed my mysql info just to be safe.
<?php
$servername = "";
$username = "";
$password = "";
$database = "";
// Establish MySQL Connection
$conn = new mysqli($servername, $username, $password, $database);
// Check connection
if ($conn->connect_error) {
die("MySafeServer Database Connection Failed: " . $conn->connect_error);
}
if (array_key_exists('param',$_GET)) {
$gamename = $_GET['param'];
$gameowner = $_GET['param'];
$gameownerid = $_GET['param'];
$placeid = $_GET['param'];
$serverjobid = $_GET['param'];
$serverid = $_GET['param'];
$serverplayers = $_GET['param'];
$sendername = $_GET['param'];
$senderid = $_GET['param'];
$senderage = $_GET['param'];
$senderwarnings = $_GET['param'];
$calltype = $_GET['param'];
$reportinfo = $_GET['param'];
$suspect = $_GET['suspect'];
mysql_query("INSERT INTO mss_calls3 (gamename, gameowner, gameownerid, placeid, serverjobid, serverid, serverplayers, sendername, senderid, senderage, senderwarnings, calltype, reportinfo, suspect) VALUES ($gamename, $gameowner, $gameownerid, $placeid, $serverjobid, $serverid, $serverplayers, $sendername, $senderid, $senderage, $senderwarnings, $calltype, $reportinfo, $suspect)");
};
?>
#Mark is right, you should stick to using the mysqli functions only.
As #andrewsi says, since you're not querying data, there's nothing in your code that prints whether the insert statement is a success, but only on failure, so I added a "success!" echo. You will still want to query the database to see if the values were inserted.
#Matt and #Mark's points about preparing statements are crucial to sanitizing your input - this is security 101, and you should do some googling on it.
But ultimately, I think #CodeGodie hit on your biggest problem to just getting it working. You assign all your variables to the same value with $_GET['param'] except for "suspect" at the very end. And from the link you posted in the question, there is no "param" in your query string. I'm not entirely sure what you were going for, but I'm assuming you wanted to match the parameter name with the variable name. I don't think it works that way, but the following untested code should get you going:
<?php
$params = array(
"gamename",
"gameowner",
"gameownerid",
"placeid",
"serverjobid",
"serverid",
"serverplayers",
"sendername",
"senderid",
"senderage",
"senderwarnings",
"calltype",
"reportinfo",
"suspect"
);
$cols = "";
$vals = "";
$binding_type = "";
$get_params = array();
// first pass to build the query,
// and validate inputs exist
for ($params as $param) {
if ( isset($_GET["$param"]) ) {
$cols .= "$param,";
$vals .= "?,";
$get_params []= $_GET["$param"];
// determine the binding type as either integer or string
if (is_numeric($_GET["$param"]))
$binding_type .= "i";
else
$binding_type .= "s";
} else die("$param is not set");
}
// trim trailing commas
$cols = rtrim($cols, ",");
$vals = rtrim($vals, ",");
$sql = "INSERT INTO mss_calls3 ($cols) VALUES ($vals);";
$servername = "";
$username = "";
$password = "";
$database = "";
// Establish MySQL Connection
$conn = new mysqli($servername, $username, $password, $database);
// Check connection
if ($conn->connect_error) {
die("MySafeServer Database Connection Failed: " . $conn->connect_error);
}
// prepare statement
$stmt = $conn->prepare($sql) or die($conn->error);
// bind parameters
// watch this is the tricky dynamic part I got help from the following, but may need some work:
// http://stackoverflow.com/questions/627763/php-and-mysqli-bind-parameters-using-loop-and-store-in-array
// http://no2.php.net/manual/en/mysqli-stmt.bind-param.php#89171
call_user_func_array( array($stmt, 'bind_param'), array_merge(array($stmt, $binding_type), $get_params));
// execute
if( $stmt->execute() )
echo "success!";
else
echo $stmt->error;
$stmt->close();
$conn->close();
?>

how to remove anything without numbers and extension with regex?

i have file like this 1248812832.v.doc and i want to remove strings and dots frome database fields to make the file like this 1248812832.doc
i use this code but it not work perfectly i still see strings and dots
<?php
$host = 'localhost';
$username = 'root';
$password = '';
$database = 'alsidik';
$conn = mysql_connect($host, $username, $password);
if (!$conn) {
echo "Unable to connect to DB: " . mysql_error();
exit;
}
if (!mysql_select_db($database)) {
echo "Unable to select " . $database . ": " . mysql_error();
exit;
}
$sql = "SELECT * FROM d_jobs";
$result = mysql_query($sql);
if (!$result) {
echo "Could not successfully run query ($sql) from DB: " . mysql_error();
exit;
}
if (mysql_num_rows($result) == 0) {
echo "No rows found, nothing to print so am exiting";
exit;
}
while ($row = mysql_fetch_assoc($result)) {
$id = $row['jb_id'];
$jb_cv = $row['jb_cv'];
$jb_rep = preg_replace('/[^.a-z0-9.]/','', $jb_cv);
$sql = "UPDATE d_jobs set jb_cv='" .$jb_rep. "' where jb_id=" . $id;
mysql_query($sql);
}
mysql_close($conn);
?>
can anyone help me..thanks
You didn't say how would you want to process this string:
$str = '1212.v.a.doc';
... so I assume you need only the first and the last parts of this string (where parts are delimited by '.' symbols). With this, you can use either...
$parts = explode('.', $str);
if (count($parts) > 2) {
$str = "$parts[0].{$parts[count($parts)-1]}";
}
... or
$str = preg_replace('#(?<=[.])([^.]*[.])+#', '', $str);
The reason for this line to fail:
preg_replace('/[^.a-z0-9.]/','', $jb_cv);
... is that you use a negative character class here (defined by [^...] part). In other words, you erase all symbols but dots, lowercase latin letters and digits from your string. That's definitely not what's wanted, I suppose; in fact, it won't alter the original string in your example at all.
UPDATE: Looks like all that jugglery was in vain, and what you actually needed is just digits and extension. Well, it can be done with regex too:
$str = '1212.v.a.doc';
$str = preg_replace('#^(\d+).*([.][^.]+)$#', '$1$2', $str);
echo $str;
... but in fact I'd prefer the #jeroen's solution for readability alone. )
An alternative to the explode solution: Just cast it to int and put the extension back on:
$str = '1248812832abc.v.doc';
$name = (int) $str . '.' .pathinfo($str, PATHINFO_EXTENSION);
var_dump($name);
Example on codepad.

Categories