How to strip subdomains to get valid root domain using PHP? - php

Ok, here's what I'm looking for: from a list of links, I'm stripping everything but the domains. The result is a mixed list of domains and domain-names which represent subdomains.
stackoverflow.com
security.stackexchange.com
whoknows.test.co.uk
you.get.it.by.now.dont.you.com
What I want to do is to trim all list entries down to their VALID (=only existing) root domains like this:
stackoverflow.com
security.stackexchange.com
test.co.uk
-fail-
Currently I explode each line into an array and work my list from back to front, using curl to check each potential root domain for it's existance... as soon as curl throws back a HTTP code >= 200 and < 400, I regard the root domain to be found. When the end of each potential domain lookup is done and no valid domain has been found at all, the domain is considered to be non-existant.
input: stackoverflow.com
test: stackoverflow.com - succeeds and is the root domain
result: stackoverflow.com - valid root domain
input: whoknows.test.co.uk
test: co.uk - fails
test: test.co.uk - succeeds (theoretically) and is the root domain
result: test.co.uk - valid root domain
input: you.get.it.by.now.dont.you.com
test: you.com - fails
test: dont.you.com - fails
test: now.dont.you.com - fails
test: by.now.dont.you.com - fails
test: it.by.now.dont.you.com - fails
test: get.it.by.now.dont.you.com - fails
test: you.get.it.by.now.dont.you.com - fails
result: you.get.it.by.now.dont.you.com - invalid domain
Is there any alternative way to do this? I would like to stop heating up my webserver's CPU with 2 to X (=near to unlimited) curl look-ups for every domain on my 100.000+ list. Also, all these lookups take a bunch of time. Maybe - so I hope - there is a quicker solution to do this.
The catch? It has to work with PHP.

There are a bunch of shortcuts to acheive what you need.
For example, you already know that .co.uk and .com are TLDs, so checking these you can obviously skip.
The problem is with all the other crazy TLDs.
I suggest you take a look at the source for ruby-domain-name
They have done a lot of work using RFCs and known data, to try and process it the right way.

So...
I've been fiddling around with this for a long time now, looking for the potential bottlenecks and after a few days of back and forth I discovered that it's actually CURL (that's waiting for the individual servers to respond with a HTTP code) that's making things slower than needed.
In the end, I opted in for a different "gethostbyname" function that takes IP6 into account to solve my problem(s).
function my_gethostbyname($host, $try_a = FALSE)
{
$dns = gethostbynamel6($host, $try_a);
if ($dns == FALSE)
{
return FALSE;
}
else
{
return $dns[0];
}
}
function gethostbynamel6($host, $try_a = FALSE)
{
$dns = array();
$dns6 = #dns_get_record($host, DNS_AAAA);
if($dns6!== FALSE)
{
$dns = array_merge($dns, $dns6);
}
if ($try_a == TRUE)
{
$dns4 = #dns_get_record($host, DNS_A);
if($dns4!== FALSE)
{
$dns = array_merge($dns, $dns4);
}
}
else
{
$dns = $dns6;
}
$ip6 = array();
$ip4 = array();
foreach ($dns as $record)
{
if ($record["type"] == "A")
{
$ip4[] = $record["ip"];
}
if ($record["type"] == "AAAA")
{
$ip6[] = $record["ipv6"];
}
}
if (count($ip6) < 1)
{
if ($try_a == TRUE)
{
if (count($ip4) < 1)
{
return FALSE;
}
else
{
return $ip4;
}
}
else
{
return FALSE;
}
}
else
{
return $ip6;
}
}
As soon as the first domain-part actually resolves to an IP, (a) the domain exists and (b) is the root domain.
This spares me major time and the trick of this is that you're only as slow as your DNS resolution and some microsecs. The curl option I used before took around 3 seconds per call (sometimes up to the full timeout range I had set to 20 secs), depending on the target server's response time - if any.
The path I now chose is easy to understand: I end up with a list of resolving domains and - when needed - I can check those using curl "on demand" or using one or more CRON jobs "on interval".
I know that it's kind of a workaround, but splitting the problem into two tasks (1 = pre-check for root domain, 2 = check if domain returns expected HTTP code) makes the whole thing faster than trying to do the complete job at once using curl.
What I've learned from this...
When checking domains, try to resolve them first so you can spare yourself the timeout burden that comes with curl.
Curl is great for many tasks, but it's not the smartest way to try to do everything with it.
When you think you can't solve a problem more than you've tried to do, split the problem in two or more parts and check again. Chances are big that you'll discover a whole new world of options to enhance what you've got.
I hope this spares someone the burden of fiddling around with an alike problem for weeks. ;)

class DomainUtils {
function __construct(){
//only these super domains
$this->superDomains = array(
'.com',
'.gov',
'.org',
'.co.uk',
'.info',
'.co',
'.net',
'.me',
'.tv',
'.mobi'
);
}
//get super domain
public function getMainDomain($domain = null){
$domainChunks = explode('.', str_ireplace($this->superDomains, '', $domain));
if(sizeof($domainChunks) == 0){
return false;
}
foreach($domainChunks as $key => $domainChunk){
if($key < sizeof($domainChunks) - 1){
$domain = str_ireplace($domainChunk . '.', '', $domain);
}
}
return $domain;
}
}

Related

PHP - How to use config file variables in a function's array?

I could not find an example of what I'm trying to accomplish. I guess I don't know the proper search words to use. I have a working script but I want to make it more flexible by adding a main, admin editable config file.
I have the following function:
function ip_is_mobile($ip) {
$pri_addrs = array(
'66.87.0.0-66.87.255.255', // Sprint mobile
'174.192.0.0-174.255.255.255' // Verizon mobile
);
$long_ip = ip2long($ip);
if($long_ip != -1) {
foreach($pri_addrs AS $pri_addr) {
list($start, $end) = explode('-', $pri_addr);
// IF IS a mobile IP
if($long_ip >= ip2long($start) && $long_ip <= ip2long($end))
return true;
}
}
return false;
}
I would like to replace the hard-coded IP address ranges, in the function, with variables or definitions which will be set in the main config file so that the config file has something similar to the following:
// Mobile IP address ranges. Add as many as needed.
$MobileIPs['0']="66.87.0.0-66.87.255.255";
$MobileIPs['1']="174.192.0.0-174.255.255.255";
$MobileIPs['2']="85.110.50.0/24";
My goal is to give the admin an easy to read and understand way of adding as many IP address ranges as necessary (probably 20 max). I'm not opposed to totally rewriting the function if there is a better, more efficient way. In addition to IP ranges, it would be advantageous if CIDR's could also be specified; as indicated in the last code line above.
What edits do I need to make to the function and what would the corresponding lines in the main config file be so that the user can add any number of ranges or CIDR's?
You can store configuration of ip ranges in separate configuration file and use require_once in your main code
ip_ranges.conf.php (configuration file)
<?php
$pri_addrs = array(
'66.87.0.0-66.87.255.255', // Sprint mobile
'174.192.0.0-174.255.255.255' // Verizon mobile
);
index.php (main code file)
function ip_is_mobile($ip) {
require_once(ip_ranges.conf.php); // include config file
$long_ip = ip2long($ip);
if($long_ip != -1) {
foreach($pri_addrs AS $pri_addr) {
list($start, $end) = explode('-', $pri_addr);
// IF IS a mobile IP
if($long_ip >= ip2long($start) && $long_ip <= ip2long($end))
return true;
}
}
return false;
}

cPanel Parked Domains Not returning array

A password was changed and cPanel broke. Fixed the password and it's still broken! I have to iterate over parked domains. I've verified the user / password combination is correct via PuTTY.
<?php
include_once('cpanel_api_xml.php');
$domain = 'example.com';
$pass = '';//etc
$user = '';//etc
$xmlapi = new xmlapi('127.0.0.1');
$xmlapi->password_auth($user,$pass);
$domains_parked = $xmlapi->listparkeddomains($user);
foreach ($domains_parked as $k1=>$v1)
{
if ($v1->domain == $domain) {$return = true; break;}
}
?>
That code generates the following error:
Invalid argument supplied for foreach()
Apparently $domains_parked is not even set! I've spent time looking at the function being called so without dumping all 86KB here is the cleaned up version of $xmlapi->listparkeddomains:
<?php
public function listparkeddomains($username, $domain = null)
{
$args = array();
if (!isset($username))
{
error_log("listparkeddomains requires that a user is passed to it");
return false;
}
if (isset($domain))
{
$args['regex'] = $domain;
return $this->api2_query($username, 'Park', 'listparkeddomains', $args);
}
return $this->api2_query($username, 'Park', 'listparkeddomains');
}
?>
I don't know what they're doing with setting a variable as the second parameter. I've called this function with and without and tested the reaction with a simple mail().
Next I tried calling the API in a more direct fashion:
$xmlapi->api2_query($username, 'Park', 'listparkeddomains')
That also does not work. Okay, let's try some really raw output testing:
echo "1:\n";
print_r($xmlapi);
echo "2:\n";
print_r($xmlapi->api2_query($user, 'Park', 'listparkeddomains'));
echo "3:\n";
$domains_parked = $xmlapi->listparkeddomains($user);
print_r($domains_parked);
die();
That outputs the following:
1: xmlapi Object (
[debug:xmlapi:private] =>
[host:xmlapi:private] => 127.0.0.1
[port:xmlapi:private] => 4099
[protocol:xmlapi:private] => https
[output:xmlapi:private] => simplexml
[auth_type:xmlapi:private] => pass
[auth:xmlapi:private] => <pass>
[user:xmlapi:private] => <user>
[http_client:xmlapi:private] => curl ) 2: 3:
I have never encountered such fragile code though I have no choice but to use it. Some help please?
So cPanel version 74 killed off the whole XML API and it doesn't frigin tell you with any error messages. I can not objectively say in the least that cPanel provides a stable platform to build anything reliable upon. You can either intentionally gimp your server from automatically updating (and potentially miss out on security updates) or every so X iterations of time completely rewrite the code again...and again...and again.

Is there a apache_request_headers alternatve for displaying HTTP Headers

I'm currently developing an app in a IGB (In-Game-Browser) for an Online MMO. For third party development the browser sends HTTP headers with in game information such as Locations, Item ID's, Items Type ID's, etc,.
It's a small script I've been using to practice with. This script works on my local server and like everyone else who's posted on this issue it does not work on my web server. I have come to the conclusion that this is due to Apache not being installed as a module. I spoke with my hosting provider. They said they could not tell me anything other than I need to find an alternative to "apache_request_headers". I've looked over all the previously posted issues on this topic on this site and I'm unable to see how it all fits together. How to use the examples on here to accomplish my end result. Like this [question]: Call to undefined function apache_request_headers()
My code:
<?php
$headers = apache_request_headers();
foreach ($headers as $header => $value) {
echo "$header: $value <br />\n";
}
?>
My error:
Fatal error: Call to undefined function apache_request_headers() in /home/ncgotggb/public_html/ezalternatives.com/index.php on line 2
I have been learning as I go this year and it's been self taught and at a fast pace so I'm still newbish to alot of these concepts. At this point tho I have no choice I'm heavily committed and need to complete it. When displaying your answer It would be greatly appreciated if you showed your solution in complete form.
It sounds like your local server is running Apache and your remote server is not, as this function only works with Apache (unless the server is running PHP 5.4.0, then it also works under FastCGI.
On the PHP Manual page for this function, one of the commenters included a replacement function that will be declared only if the built-in one doesn't exist. I haven't tested this, but I've seen the same function posted elsewhere.
if( !function_exists('apache_request_headers') ) {
function apache_request_headers() {
$arh = array();
$rx_http = '/\AHTTP_/';
foreach($_SERVER as $key => $val) {
if( preg_match($rx_http, $key) ) {
$arh_key = preg_replace($rx_http, '', $key);
$rx_matches = array();
// do some nasty string manipulations to restore the original letter case
// this should work in most cases
$rx_matches = explode('_', $arh_key);
if( count($rx_matches) > 0 and strlen($arh_key) > 2 ) {
foreach($rx_matches as $ak_key => $ak_val) {
$rx_matches[$ak_key] = ucfirst($ak_val);
}
$arh_key = implode('-', $rx_matches);
}
$arh[$arh_key] = $val;
}
}
return( $arh );
}
}
I found that my site in ISP Config was set to have PHP as 'Fast-CGI' - changing this to 'MOD-PHP' fixed things nicely.

get website ip using php

I need to fetch the given website ip address using php, that is ip address of server in which website is hosted.
For that i've used gethostbyname('**example.com*'). It works fine when the site is not redirected. for example if i used this function to get google.com, it gives "74.125.235.20".
When i tried it for "lappusa.com" it gives "lappusa.com". Then i tried this in browser it is redirecting to "http://lappusa.lappgroup.com/" . I checked the http status code it shows 200.
But i need to get ip address even if site was redirected, like if lappusa.com is redirected to lappusa.lappgroup.com then i need to get ip for redirected url.
How should i get this? any help greatly appreciated, Thanks!.
The problem is not the HTTP redirect (which is above the level gethostbyname operates), but that lappusa.com does not resolve to any IP address and therefore can't be loaded in any browser. What your browser did was automatically try prepending www..
You can reproduce that behavior in your code. Also note that multiple IPs (version 4 and 6) can be associated with one domain:
<?php
function getAddresses($domain) {
$records = dns_get_record($domain);
$res = array();
foreach ($records as $r) {
if ($r['host'] != $domain) continue; // glue entry
if (!isset($r['type'])) continue; // DNSSec
if ($r['type'] == 'A') $res[] = $r['ip'];
if ($r['type'] == 'AAAA') $res[] = $r['ipv6'];
}
return $res;
}
function getAddresses_www($domain) {
$res = getAddresses($domain);
if (count($res) == 0) {
$res = getAddresses('www.' . $domain);
}
return $res;
}
print_r(getAddresses_www('lappusa.com'));
/* outputs Array (
[0] => 66.11.155.215
) */
print_r(getAddresses_www('example.net'));
/* outputs Array (
[0] => 192.0.43.10
[1] => 2001:500:88:200::10
) */
They redirect using a META tag in the HTML source. You will need to parse the actual sourcecode to catch this.
Did you try sending HttpRequest to certain page and then parsing the response headers? I'm not sure, but it should contain some IP or host info...

Check if a user is root

How can i verify if a user is root in a PHP script ? What is the command ?
I tried something like that :
exec("su -l login < `echo password`");
but the su command can not receive password...
Note that the machine is isolated from internet so I can run PHP as root if needed.
EDIT:
I don't want to know if the current user who run the script is root or not.
I have a list of users in my PHP script and I want to know for each login if he has root privileges.
How about posix_getuid()?
if (0 == posix_getuid()) {
echo "Running as root.";
} else {
echo "not root";
}
First, ask yourself what exactly defines a login "having root privileges". AFAICT there are 2 basic solutions.
The old-school way, where sysadmins create multiple accounts with uid 0, which I - and I'm certainly not alone in this - consider to be a nightmare. In this scenario you could check all users in your list using posix_getpwnam and see if their uid matches 0.
The following code snippet does just that, $privileged will contain the users with root privileges :
$logins = array('root', 'john', 'guest', 'foo');
$privileged = array();
foreach($logins as $login) {
$userInfo = posix_getpwnam($login);
if ($userInfo !== FALSE) {
if ($userInfo['uid'] == 0) {
$privileged[] = $login;
}
}
}
The other (and imho only sane) way to do this is to add all users with root/administrative privileges to a specific group (wheel or admin are already used in different Linux distributions, find out which one works for you). This scenario is even simpler, since you can use posix_getgrnam to fetch all members in a specific group.
The following code snippet will match an array of logins you provide, and see who's a member with specific privileges, again $privileged will contain the result (ie. the users in your list that are a member of the group you specified) :
$logins = array('root', 'john', 'guest', 'foo');
$privileged = array();
$groupInfo = posix_getgrnam('admins');
if ($groupInfo !== FALSE) {
$privileged = array_intersect($logins, $groupInfo['members']);
}
Try This .
<?php
if (posix_getuid() == 0){
echo "This is root !";
// add more for root
} else {
echo "This is non-root";
}
?>
If you really mean "is root", then you can just check for whoami, and see if it comes up 'root'
exec("whoami");
If it's a smart thing to do is a different question ;)
Rewritten after your comment
"I don't want to know if the user who
run the script is root or no. I have
to check in a PHP script for some
login/password if they are root or
not"
I now understood that you need to perform a root authentication in PHP.
I suggest to use pwauth instead of whoami/login, etc.
Here is an example on how to use it from PHP, while I believe there can be a simpler way of testing.
If you want to see if a certain system user (as opposed to a web-service user) has root priviliedges, you can use the posix_getpwnam() function:
<?php
$u = posix_getpwnam("username");
if ($u == FALSE) {
print "no-such-user";
} elseif ($u["uid"] == 0) {
print "root";
} else {
print "non-root";
};
?>
Keep in mind that this only checks the username. If you also need to check the password you actually have to try to authenticate with the system.

Categories