get server ram with php - php

Is there a way to know the avaliable ram in a server (linux distro) with php (widthout using linux commands)?
edit: sorry, the objective is to be aware of the ram available in the server / virtual machine, for the particular server (even if that memory is shared).

If you know this code will only be running under Linux, you can use the special /proc/meminfo file to get information about the system's virtual memory subsystem. The file has a form like this:
MemTotal: 255908 kB
MemFree: 69936 kB
Buffers: 15812 kB
Cached: 115124 kB
SwapCached: 0 kB
Active: 92700 kB
Inactive: 63792 kB
...
That first line, MemTotal: ..., contains the amount of physical RAM in the machine, minus the space reserved by the kernel for its own use. It's the best way I know of to get a simple report of the usable memory on a Linux system. You should be able to extract it via something like the following code:
<?php
$fh = fopen('/proc/meminfo','r');
$mem = 0;
while ($line = fgets($fh)) {
$pieces = array();
if (preg_match('/^MemTotal:\s+(\d+)\skB$/', $line, $pieces)) {
$mem = $pieces[1];
break;
}
}
fclose($fh);
echo "$mem kB RAM found"; ?>
(Please note: this code may require some tweaking for your environment.)

Using /proc/meminfo and getting everything into an array is simple:
<?php
function getSystemMemInfo()
{
$data = explode("\n", file_get_contents("/proc/meminfo"));
$meminfo = array();
foreach ($data as $line) {
list($key, $val) = explode(":", $line);
$meminfo[$key] = trim($val);
}
return $meminfo;
}
?>
var_dump( getSystemMemInfo() );
array(43) {
["MemTotal"]=>
string(10) "2060700 kB"
["MemFree"]=>
string(9) "277344 kB"
["Buffers"]=>
string(8) "92200 kB"
["Cached"]=>
string(9) "650544 kB"
["SwapCached"]=>
string(8) "73592 kB"
["Active"]=>
string(9) "995988 kB"
...

Linux commands can be run using the exec function in PHP. This is efficient and will do the job(if objective is to get the memory).
Try the following code:
<?php
exec("free -mtl", $output);
print_r($output);
?>

Small and tidy function to get all of its values associated to their keys.
$contents = file_get_contents('/proc/meminfo');
preg_match_all('/(\w+):\s+(\d+)\s/', $contents, $matches);
$info = array_combine($matches[1], $matches[2]);
// $info['MemTotal'] = "2047442"

I don't think you can access the host server memory info without a special written PHP extension. The PHP core library does not allow (perhaps for security reasons) to access the extended memory info.
However, if your script has access to the /proc/meminfo then you can query that special file and grab the info you need. On Windows (although you've not asked for it) we can use the com_dotnet PHP extension to query the Windows framework via COM.
Below you can find my getSystemMemoryInfo that returns that info for you no matter if you run the script on a Linux/Windows server. The wmiWBemLocatorQuery is just a helper function.
function wmiWBemLocatorQuery( $query ) {
if ( class_exists( '\\COM' ) ) {
try {
$WbemLocator = new \COM( "WbemScripting.SWbemLocator" );
$WbemServices = $WbemLocator->ConnectServer( '127.0.0.1', 'root\CIMV2' );
$WbemServices->Security_->ImpersonationLevel = 3;
// use wbemtest tool to query all classes for namespace root\cimv2
return $WbemServices->ExecQuery( $query );
} catch ( \com_exception $e ) {
echo $e->getMessage();
}
} elseif ( ! extension_loaded( 'com_dotnet' ) )
trigger_error( 'It seems that the COM is not enabled in your php.ini', E_USER_WARNING );
else {
$err = error_get_last();
trigger_error( $err['message'], E_USER_WARNING );
}
return false;
}
// _dir_in_allowed_path this is your function to detect if a file is withing the allowed path (see the open_basedir PHP directive)
function getSystemMemoryInfo( $output_key = '' ) {
$keys = array( 'MemTotal', 'MemFree', 'MemAvailable', 'SwapTotal', 'SwapFree' );
$result = array();
try {
// LINUX
if ( ! isWin() ) {
$proc_dir = '/proc/';
$data = _dir_in_allowed_path( $proc_dir ) ? #file( $proc_dir . 'meminfo' ) : false;
if ( is_array( $data ) )
foreach ( $data as $d ) {
if ( 0 == strlen( trim( $d ) ) )
continue;
$d = preg_split( '/:/', $d );
$key = trim( $d[0] );
if ( ! in_array( $key, $keys ) )
continue;
$value = 1000 * floatval( trim( str_replace( ' kB', '', $d[1] ) ) );
$result[$key] = $value;
}
} else // WINDOWS
{
$wmi_found = false;
if ( $wmi_query = wmiWBemLocatorQuery(
"SELECT FreePhysicalMemory,FreeVirtualMemory,TotalSwapSpaceSize,TotalVirtualMemorySize,TotalVisibleMemorySize FROM Win32_OperatingSystem" ) ) {
foreach ( $wmi_query as $r ) {
$result['MemFree'] = $r->FreePhysicalMemory * 1024;
$result['MemAvailable'] = $r->FreeVirtualMemory * 1024;
$result['SwapFree'] = $r->TotalSwapSpaceSize * 1024;
$result['SwapTotal'] = $r->TotalVirtualMemorySize * 1024;
$result['MemTotal'] = $r->TotalVisibleMemorySize * 1024;
$wmi_found = true;
}
}
// TODO a backup implementation using the $_SERVER array
}
} catch ( Exception $e ) {
echo $e->getMessage();
}
return empty( $output_key ) || ! isset( $result[$output_key] ) ? $result : $result[$output_key];
}
Example on a 8GB RAM system
print_r(getSystemMemoryInfo());
Output
Array
(
[MemTotal] => 8102684000
[MemFree] => 2894508000
[MemAvailable] => 4569396000
[SwapTotal] => 4194300000
[SwapFree] => 4194300000
)
If you want to understand what each field represent then read more.

It is worth noting that in Windows this information (and much more) can be acquired by executing and parsing the output of the shell command: systeminfo

exec("grep MemTotal /proc/meminfo", $aryMem);
$aryMem[0] has your total ram minus kernel usage.

I don't remember having ever seen such a function -- its kind of out the scope of what PHP is made for, actually.
Even if there was such a functionnality, it would probably be implemented in a way that would be specific to the underlying operating system, and wouldn't probably work on both Linux and windows (see sys_getloadavg for an example of that kind of thing)

// helpers
/**
* #return array|null
*/
protected function getSystemMemInfo()
{
$meminfo = #file_get_contents("/proc/meminfo");
if ($meminfo) {
$data = explode("\n", $meminfo);
$meminfo = [];
foreach ($data as $line) {
if( strpos( $line, ':' ) !== false ) {
list($key, $val) = explode(":", $line);
$val = trim($val);
$val = preg_replace('/ kB$/', '', $val);
if (is_numeric($val)) {
$val = intval($val);
}
$meminfo[$key] = $val;
}
}
return $meminfo;
}
return null;
}
// example call to check health
public function check() {
$memInfo = $this->getSystemMemInfo();
if ($memInfo) {
$totalMemory = $memInfo['MemTotal'];
$freeMemory = $memInfo['MemFree'];
$swapTotalMemory = $memInfo['SwapTotal'];
$swapFreeMemory = $memInfo['SwapFree'];
if (($totalMemory / 100.0) * 30.0 > $freeMemory) {
if (($swapTotalMemory / 100.0) * 50.0 > $swapFreeMemory) {
return new Failure('Less than 30% free memory and less than 50% free swap space');
}
return new Warning('Less than 30% free memory');
}
}
return new Success('ok');
}

Related

apache_request_headers function for NGINX

will apache_request_headers function work on NGINX Web
Server. If not what is function for NGINX parallel to it
Some people have written their own functions on the PHP docs site.
https://www.php.net/manual/en/function.apache-request-headers.php
<?php
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 );
}
}
See if that helps (haven't tried it).
As per the documentation:
https://www.php.net/manual/en/function.apache-request-headers.php
Fetches all HTTP request headers from the current request. Works in the Apache, FastCGI, CLI, FPM and NSAPI server module in Netscape/iPlanet/SunONE webservers.
If you're running PHP via an FPM socket on UNIX, or using the FastCGI interface, this function will work. The fact is begins with apache is misleading, but is hardly atypical of PHP function naming.

Sorting files in an array by the ocurrences of a word in it, php

I'm making a search bar that searches files in a directory that have the word searched, then I want it to be added to an array by order of which one has more times the word asked to the one with less.
I'm working on PHP this is my code:
<?php
if(isset($_POST['busqueda'])){
$variable = utf8_encode($_POST['busqueda']);
}
$Array1 = array();
foreach(glob("*.txt") as $filename) {
$contents = file_get_contents($filename);
if (strpos($contents, $variable)){
$Array1[] = $filename;
}
}
I don't know how to do it exactly, I think that I should use substr_count(file_get_contents($Array1[$position1])) or something like that but I'm unsure how to make the sorting system, can someone help me!
print_r($Array1);
for($var1=0; $var1<sizeof($Array1); $var1++){
echo "times on the file: ".$Array1[$var1]."<br>";
echo substr_count(file_get_contents($Array1[$var1]));
}
?>
You can use the substr_count itself. Then you need to use arsort to sort the array.
$Array1 = array();
foreach (glob("*.txt") as $filename) {
$contents = file_get_contents($filename);
if ( ($count = substr_count($contents, $variable)) ) {
$Array1[$filename] = $count;
}
}
arsort($Array1) ;
print_r($Array1);
foreach ($Array1 as $file => $count) {
echo "times on the file($file): $count <br>";
}
Bash (available on at least Linux and Mac operating systems) makes it extremely easy to accomplish your task, because you can call commands through PHP's exec function, assuming it is not disabled by an administrator. If you're on Windows, then this will probably not work, but most people are using Linux for a production environment, so I thought this answer would be worthy of posting.
The following function is taken from CodeIgniter's file helper and only serves to fetch an array of filenames from a specified directory. If you don't need a function like this because you are getting your filenames from somewhere else, just note that this function can include the full file path for each file, and that's why I used it.
function get_filenames($source_dir, $include_path = FALSE, $_recursion = FALSE)
{
static $_filedata = array();
if ($fp = #opendir($source_dir))
{
// reset the array and make sure $source_dir has a trailing slash on the initial call
if ($_recursion === FALSE)
{
$_filedata = array();
$source_dir = rtrim(realpath($source_dir), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
}
while (FALSE !== ($file = readdir($fp)))
{
if (#is_dir($source_dir.$file) && strncmp($file, '.', 1) !== 0)
{
get_filenames($source_dir.$file.DIRECTORY_SEPARATOR, $include_path, TRUE);
}
elseif (strncmp($file, '.', 1) !== 0)
{
$_filedata[] = ($include_path == TRUE) ? $source_dir.$file : $file;
}
}
return $_filedata;
}
else
{
return FALSE;
}
}
Now that I can fetch an array of filenames easily, I'd do this:
/**
* Here you can see that I am searching
* all of the files in the script-library
* directory for the word "the"
*/
$searchWord = 'the';
$directory = '/var/www/htdocs/script-library';
$filenames = get_filenames(
$directory,
TRUE
);
foreach( $filenames as $file )
{
$counts[$file] = exec("tr ' ' '\n' < " . $file . " | grep " . $searchWord . " | wc -l");
}
arsort( $counts );
echo '<pre>';
print_r( $counts );
echo '</pre>';
For a good explaination of how that works, see this: https://unix.stackexchange.com/questions/2244/how-do-i-count-the-number-of-occurrences-of-a-word-in-a-text-file-with-the-comma
I tested this code locally and it works great.

php Read file content to a static array

I am writing a code for Bayesian Filter. For a particular word, I want to check if the word is in the stop words list or not, I populate from stop word list from a file on my pc.
Because I have to do this for many words I don't want to read the StopWord file from my pc again and again.
I want to do something like this
function isStopWord( $word ){
if(!isset($stopWordDict))
{
$stopWords = array();
$handle = fopen("StopWords.txt", "r");
if( $handle )
{
while( ( $buffer = fgets( $handle ) ) != false )
{
$stopWords[] = trim( $buffer );
}
}
echo "StopWord opened";
static $stopWordDict = array();
foreach( $stopWords as $stopWord )
$stopWordDict[$stopWord] = 1;
}
if( array_key_exists( $word, $stopWordDict ) )
return true;
else
return false;
}
I thought by using a static variable it will solve the issue, but it doesn't. Kindly help.
Put the static declaration at the beginning of the function:
function isStopWord( $word ){
static $stopWordDict = array();
if(!$stopWordDict)
{
$stopWords = file("StopWords.txt");
echo "StopWord opened";
foreach( $stopWords as $stopWord ) {
$stopWordDict[trim($stopWord)] = 1;
}
}
if( array_key_exists( $word, $stopWordDict ) )
return true;
else
return false;
}
This will work since an empty array is considered falsy.

turning this trainwreck of a function into a recursive one

I've been trying to build this recursive function for the better part of a day now, but I just can't seem to get it to work the way I want.
First, I have a property which holds some data that the function have to access:
$this->data
And then I have this string which the intention is to turn into a relative path:
$path = 'path.to.%id%-%folder%.containing.%info%';
The part of the string that are like this: %value% will load some dynamic values found in the $this->data property (like so: $this->data['id']; or $this->data['folder'];
and to make things really interesting, the property can reference itself again like so: $this->data['folder'] = 'foldername.%subfolder%'; and also have two %values% separated by a - that would have to be left alone.
So to the problem, I've been trying to make a recursive function that will load the dynamic values from the data property, and then again if the new value contains another %value% and so on until no more %value%'s are loaded.
So far, this is what I've been able to come up with:
public function recursiveFolder( $folder, $pathArr = null )
{
$newPathArr = explode( '.', $folder );
if ( count ( $newPathArr ) !== 1 )
{
foreach( $newPathArr as $id => $folder )
{
$value = $this->recursiveFolder( $folder, $newPathArr );
$resultArr = explode( '.', $value );
if ( count ( $resultArr ) !== 1 )
{
foreach ( $resultArr as $nid => $result )
{
$nvalue = $this->recursiveFolder( $result, $newPathArr );
$resultArr[$nid] = $nvalue;
}
}
$resultArr = implode( '.',$resultArr );
$newPathArr[$id] = $resultArr;
}
}
else
{
$pattern = '/%(.*?)%/si';
preg_match_all( $pattern, $folder, $matches );
if ( empty( $matches[0] ) )
{
return $folder;
}
foreach ( $matches[1] as $mid => $match )
{
if ( isset( $this->data[$match] ) && $this->data[$match] != '' )
{
$folder = str_replace( $matches[0][$mid], $this->data[$match], $folder );
return $folder;
}
}
}
return $newPathArr;
}
Unfortunately it is not a recursive function at all as it grinds to a halt when it has multiple layers of %values%, but works with two layers -barely-. (I just coded it so that it would work at a bare minimalistic level this point).
Here's how it should work:
It should turn:
'files.%folder%.blog-%type%.and.%time%'
into:
'files.foldername.blog-post.and.2013.feb-12th.09'
based on this:
$data['folder'] = 'foldername';
$data['type'] = 'post';
$data['time'] = '%year%.%month%-%day%';
$data['year'] = 2013;
$data['month'] = 'feb';
$data['day'] = '12th.%hour%';
$data['hour'] = '09';
Hope you can help!
Jay
I don't see the need for this too be solved recursively:
<?php
function putData($str, $data)
{
// Repeat the replacing process until no more matches are found:
while (preg_match("/%(.*?)%/si", $str, $matches))
{
// Use $matches to make your replaces
}
return $str;
}
?>

Retrieve the country code in PHP

I'm a little lost with that.
How can I retrieve the ISO country code of the visitors at one php page?
Thanks advance
You can either do this by Geolocation of the IP or by inspecting the right headers.
Usually you want the latter, since it tells you which languages the browser/system uses. You will only want to use geolocation when you want to know the physical location.
The header is stored in $_SERVER['HTTP_ACCEPT_LANGUAGE']. It contains comma-separated entries, e.g.: en-GB,en;q=0.8,en-US;q=0.6,nl;q=0.4 (my own)
The HTTP Accept Language parameters seperates it's languages by a comma, it's properties by a semicolon. The q-value is from 0 to 1, with 1 being the highest/most preferred. Here is some naive and untested code to parse it:
$langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
$preffered = "";
$prefvalue = 0;
foreach($langs as $lang){
$info = explode(';', $lang);
$val = (isset($lang[1])?$lang[1];1);
if($prefvalue < $val){
$preferred = $lang[0];
$prefvalue = $val;
}
}
Much simpler is it if you want to test if a specific language is accepted, e.g. Spanish (es):
if(strpos($_SERVER['HTTP_ACCEPT_LANGUAGE'], "es") !== false){
// Spanish is supported
}
I think you could use this php script which uses an ip and prints out a country code
Example
http://api.hostip.info/country.php?ip=4.2.2.2
Gives US
Check out
http://www.hostip.info/use.html
for more info.
A library i use myself and can recommend, is MaxMind GeoLite Country. To get the country code, you need only to copy 2 files to your server, the php code geoip.inc and the binary data GeoIP.dat.
Using the library is also very straightforward:
function ipToCountry()
{
include_once('geoip/geoip.inc');
$gi = geoip_open(__DIR__ . '/geoip/GeoIP.dat', GEOIP_STANDARD);
$result = geoip_country_code_by_addr($gi, $_SERVER['REMOTE_ADDR']);
geoip_close($gi);
return $result;
}
This will use GeoIp and fall back to accept_lang
class Ip2Country
{
function get( $target )
{
$country = false;
if( function_exists( 'geoip_record_by_name' ) )
$country = $this->getFromIp( $target );
if( !$country && isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) )
$country = $this->getFromLang( $_SERVER['HTTP_ACCEPT_LANGUAGE'] );
return $country;
}
function getFromIp( $target )
{
$dat = #geoip_record_by_name( $target );
return ( isset( $dat['country_code'] ) ) ? mb_strtolower( $dat['country_code'] ) : false;
}
function getFromLang( $str )
{
$info = array();
$langs = explode( ',', $str );
foreach( $langs as $lang )
{
$i = explode( ';', $lang );
$j = array();
if( !isset( $i[0] ) ) continue;
$j['code'] = $i[0];
if( strstr( $j['code'], '-' ) )
{
$parts = explode( '-', $j['code'] );
$j['lang'] = $parts[0];
$j['country'] = mb_strtolower( $parts[1] );
}
$info[] = $j;
}
return ( isset( $info[0]['country'] ) ) ? $info[0]['country'] : false;
}
}
$x = new Ip2Country();
var_dump( $x->get( 'canada.ca' ) );

Categories