TeamSpeak: Query Number of Connected Clients - php

I am currently using TeamSpeak's ServerQuery feature to display all channels and connected users via PHP on my website. Right now it looks like this: (apologies for the crude usernames/channel titles)
It works to display channels and user names. However, I do not want it to do this.
Instead of showing all channels and user names that have connected, I would prefer it just to fetch the amount of users that are currently connected and the maximum amount of users that can connect and display them as seen above. (Along with the server status, i.e online or offline.)
This is the API I am using to connect to the TeamSpeak server via PHP.

Discovered a solution by myself!
Framework
TeamSpeak PHP Framework.
We only really need the libraries folder for this situation, so feel free to delete the docs and images folders.
--
PHP (Thanks to SilentStorm)
<?php
date_default_timezone_set("Europe/London");
require_once("libraries/TeamSpeak3/TeamSpeak3.php");
TeamSpeak3::init();
header('Content-Type: text/html; charset=utf8');
$status = "offline";
$count = 0;
$max = 0;
try {
$ts3 = TeamSpeak3::factory("serverquery://<USER>:<PASSWORD>#<SERVER IP>:<QUERY PORT>/?server_port=<SERVER PORT>&use_offline_as_virtual=1&no_query_clients=1");
$status = $ts3->getProperty("virtualserver_status");
$count = $ts3->getProperty("virtualserver_clientsonline") - $ts3->getProperty("virtualserver_queryclientsonline");
$max = $ts3->getProperty("virtualserver_maxclients");
}
catch (Exception $e) {
echo '<div style="background-color:red; color:white; display:block; font-weight:bold;">QueryError: ' . $e->getCode() . ' ' . $e->getMessage() . '</div>';
}
echo '<span class="ts3status">TS3 Server Status: ' . $status . '</span><br/><span class="ts3_clientcount">Clients online: ' . $count . '/' . $max . '</span>';
?>
Customise
- ServerQuery username (Can be found in TeamSpeak, Tools -> ServerQuery Login
- ServerQuery password (Can be found in TeamSpeak, Tools -> ServerQuery Login
- The server's IP address
- The ServerQuery port (Default - 10011)
- The server's port (Default - 9987)
Save the file appropriately, in the same directory that includes the libraries folder. To display it on a page put the code:
<?php
include('path/to/file/filename.php');
?>
This will then display the TeamSpeak server information on the page! Hope I could help.

Related

Can web robots inflate download counts?

I have a PHP program connected to an MYSQL database on a website.
Upon clicking a link to download a file, the program reads an integer field from the database, increments it, then puts the number back, to count the number of downloads. That program works. The download counts, however, over time, seem to be moderately inflated.
Could the download counts be incremented by web robots following the links to download the files? If so, would telling the web robots to ignore the download page on the website, using the robots.txt file, solve the inflated count problem?
Here is the PHP code:
function updateDownloadCounter($downloadPath, $tableName, $fileNameField, $downloadCountField, $idField)
{
require("v_config.php");
if(isset($_REQUEST["file_id"]) && is_numeric($_REQUEST["file_id"])) {
try
{
$sql = "SELECT * FROM " . $tableName . " WHERE file_id = " . $_REQUEST[$idField];
$connection = new PDO($dsn, $username, $password, $options);
$statement = $connection->prepare($sql);
$statement->execute();
$result = $statement->fetchAll();
if ($result && $statement->rowCount() == 1)
{
foreach ($result as $row)
{
if(is_file($_SERVER['DOCUMENT_ROOT'].$downloadPath . $row[$fileNameField]))
{
$count = $row[$downloadCountField] + 1;
$sql = "UPDATE " . $tableName . " SET " . $downloadCountField . " = " . $count . " WHERE file_id = " . $_REQUEST[$idField];
$statement = $connection->prepare($sql);
$statement->execute();
$documentLocationAndName = $downloadPath . $row[$fileNameField];
header('Location:' . $documentLocationAndName);
}
}
}
}
catch(PDOException $error)
{
echo $sql . "<br>" . $error->getMessage();
}
}
}
The answer to both of your questions is yes.
When a crawler indexes your website, it also looks for related content, akin to creating a sitemap. The first place it looks for related content on a page are the direct links. If you're linking to your files directly on your download page, the crawler will also attempt to index those links.
Preventing the crawlers from seeing your download page with robots.txt would prevent this problem, but then you'd be losing potential SEO. And what if a third party links to your downloads directly? If they have their downloads page indexed, your links will still be visible to crawlers.
Fortunately, you can disable this behaviour. Simply tell the crawlers that the links on the download page are all canonical ones, by adding the following to the <head> section of the downloads page:
<link rel="canonical" href="http://www.example.com/downloads" />
Considering the parameters are essentially different 'pages', crawlers will think that /downloads?file_id=1 is different to /downloads. Adding the above line will inform them that it is the same page, and that they don't need to bother.
Assuming that you have actual files that are being indexed (such as PDFs), you can prevent crawlers from indexing them in your .htaccess or httpd.conf:
<Files ~ "\.pdf$">
Header set X-Robots-Tag "noindex, nofollow"
</Files>
As a fallback, you could always check who is attempting to download the file in the PHP itself! It depends how pedantic you want to be (as there are a lot of different crawlers), but this function works pretty well:
function bot_detected() {
return (
isset($_SERVER['HTTP_USER_AGENT'])
&& preg_match('/bot|crawl|slurp|spider|mediapartners/i', $_SERVER['HTTP_USER_AGENT'])
);
}
Then simply call it as a conditional before running your try:
if (!bot_detected()) {
try { } // Will only get executed for real visitors
}
Also, as an aside, I'd recommend using $_GET["file_id"] over $_REQUEST["file_id"]. $_REQUEST combines $_GET with both $_POST and $_COOKIE, which tend to be used in rather different ways. While this is technically secure if you're only retrieving data, it's far safer to limit the request to a simple $_GET.
Hope this helps! :)

Failure of PHP AD LDAP script ONLY when passed variables

Sample AD LDAP Live Lookup PHP from Helpspot
Okay so I am using the above sample php LDAP script to lookup user info in our ticketing system. I am running into some issues however (these are probably due to my very rudimentary understanding of PHP). I know the script is sort of working because if I hit the URL for the script in my browser it will spit back a list of all users in the domain until it hit the return limit and just stops. I am sure I could get it to spit back more, but that is not really the issue right now. Because I am getting data from my domain I am assuming that my creds and binds are good in the script. We use the credentials, server, etc on all our MFP's for their global address list without issue so I am positive I am good there. The problem arises when you pass anything to it to do a lookup. I receive an error that states:
ldap search failed: Operations error
When I tweak the script to give me a little more info it points me back to this line:
$search = ldap_search($ad, $dn, $filter, $attrs)
or die ("ldap search failed: ".ldap_error($ad));
Which I had suspected given the error I was getting is present in this line. So I am assuming one of those defined variables is the culprit causing me problems. This is where i start to get lost. I am not understanding why asking it to narrow the results returned would break this? Any suggestions? Or is there anything more I need to share?
Thank you #heiglandreas that post helped me immensely. Using the script being run in that section I was able to grab some pieces that allowed my script to function properly. I am not sure exactly why my environment didn't care for my first script, I suspect the change in location in the script of certain steps and the changed formatting of the bind helped. My script now looks like:
<?php
header('Content-type: text/xml');
$hostname="ldap://SERVER IP ADDRESS";
$ds=ldap_connect($hostname, 389);
$user = "domain\username";
$pswd = "PASSWORD";
ldap_set_option ($ds, LDAP_OPT_REFERRALS, 0) or die('Unable to set LDAP opt referrals');
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3) or die('Unable to set LDAP protocol version');
if ($ds)
{
$dn = "DC=DOMAIN,DC=local";
if (!($ldapc=ldap_bind($ds, $user, $pswd))) {
echo "<p>Error:" . ldap_error($ds) . "</p>";
echo "<p>Error number:" . ldap_errno($ds) . "</p>";
echo "<p>Error:" . ldap_err2str(ldap_errno($ds)) . "</p>";
die;
}
$attributes = array('employeeID','givenname','sn','mail','telephoneNumber');
if(!empty($_GET['customer_id'])){ //If an ID is passed in use that to make a direct lookup
$filter = 'employeeID='.$_GET['customer_id'].'*';
}elseif(!empty($_GET['email'])){ //If no ID then try email
$filter = 'mail='.$_GET['email'].'*';
}elseif(!empty($_GET['last_name'])){ //If no ID or email then search on last name
$filter = 'sn='.$_GET['last_name'].'*';
}elseif(!empty($_GET['first_name'])){ //Try first name if no ID,email,last name
$filter = 'givenname='.$_GET['first_name'].'*';
}else{
$filter = 'sn='.'*'; //Return everyone
}
$search = ldap_search($ds, $dn, $filter, $attributes)
or die ("ldap search failed: ".ldap_error($ds));
$entries = ldap_get_entries($ds, $search);
echo '<?xml version="1.0" encoding="utf-8"?>';
}
?>
<livelookup version="1.0" columns="first_name,last_name, email">
<?php for ($i=0; $i < $entries["count"]; $i++) : ?>
<customer>
<customer_id><?php if(isset($entries[$i]['employeeID'][0])){ echo htmlspecialchars($entries[$i]['employeeID'][0]); } ?></customer_id>
<first_name><?php if(isset($entries[$i]['givenname'][0])){ echo htmlspecialchars($entries[$i]['givenname'][0]); } ?></first_name>
<last_name><?php if(isset($entries[$i]['sn'][0])){ echo htmlspecialchars($entries[$i]['sn'][0]); } ?></last_name>
<email><?php if(isset($entries[$i]['mail'][0])){ echo htmlspecialchars($entries[$i]['mail'][0]); } ?></email>
<phone><?php if(isset($entries[$i]['telephonenumber'][0])){ echo htmlspecialchars($entries[$i]['telephonenumber'][0]); } ?></phone>
<!-- Add custom elements here. Simply add them to $attrs above and then output the tag like the others here -->
</customer>
<?php endfor; ?>
</livelookup>
<?php ldap_unbind($ds); ?>

I can't seem to delete all messages except the most recent

I'm using the following code which you may recognise from php.net to delete all the emails in my inbox:
function deleteEmails($emailAddress)
{
// connect to gmail with your credentials
$hostname = '{imap.gmail.com:993/imap/ssl}INBOX';
$username = $emailAddress; # e.g somebody#gmail.com
$password = '****************';
// try to connect
$inbox = imap_open($hostname,$username,$password) or die('Cannot download information: ' . imap_last_error());
$check = imap_mailboxmsginfo($inbox);
echo "Messages before delete: " . $check->Nmsgs . "<br />\n";
imap_delete($inbox, '1:*');
$check = imap_mailboxmsginfo($inbox);
echo "Messages after delete: " . $check->Nmsgs . "<br />\n";
imap_expunge($inbox);
$check = imap_mailboxmsginfo($inbox);
echo "Messages after expunge: " . $check->Nmsgs . "<br />\n";
imap_close($inbox);
}
which helps deal with a clog in my account that happens on occasion if I let it get out of hand. However, what I really need is for it to delete all my email except the most recent one. I have tried to change imap_delete($inbox, '1:*'); to imap_delete($inbox, '2:*'); but this just caused it to not work at all.
What am I missing?
EDIT
With advise below I tried the following:
imap_delete($inbox, "2:$check->Nmsgs");
But interestingly it deleted all but one of the 'conversations' but in gmail 'conversations' can max out at 61 emails! I'm not sure how to get around this. Also, the deleted ones returned after a few mins...
I know gmail does some interesting stuff with just tagging it differently and putting it in an All Mail folder, since there aren't actual "Folders" like on most IMAP systems. Have you tried just giving it a range, such as
imap_delete($inbox,2:$check->Nmsgs);
If that doesn't work, you might have to just loop through marking them for deletion and then expunge after that.
I found the issue. Gmail by default is set up using 'conversations' meaning any emails coming in with the same subject get grouped together. This screws with everything but it can be turned off in gmail settings. Once done I needed to make sure I was deleting all but the most recent. using imap_delete($inbox,2:$check->Nmsgs); deleted all but the oldest. so the following code did it for me:
$emails = ($check->Nmsgs)-1;
imap_delete($inbox, '1:' . $emails);
so that I was getting the numbers but was deleting all up to the last one to come in (the most recent)
Done

How can I appear as online when I login to my Android app?

I have made an app in which the scenario is as below:
user can register and that registration information goes to a PHP server and is stored in a MySQL database.
This is my PHP file:
<?php
// Check if he wants to login:
if (!empty($_POST[username]))
{
require_once("connect.php");
// Check if he has the right info.
$query = mysql_query("SELECT * FROM gen_users
WHERE username = '$_POST[username]'
AND password = '$_POST[password]'")
or die ("Error - Couldn't login user.");
$row = mysql_fetch_array($query)
or die ("Error - Couldn't login user.");
if (!empty($row[username])) // he got it.
{
echo "success";
exit();
}
else // bad info.
{
echo "comes in else part";
exit();
}
}
?>
If I enter a username and password that match from MySQL database, then it throws the word "success" to Android class and will go further in the app. I have a display list-view of registered people in my app.
How can I know how many people use my app right now? The people who are logged-in in app are to appear as a green image in a list view and other people are to appear as a red image.
How can I achieve this?
in addition to #GlaciesofPacis answer you can do one of the following:
send a request for the server in intervals and check who's online or not.
you can use a client-server mechanism - which -is much more complicated but much more efficient and elegant - and make the server push to all online clients when some client is now off or on.
i don't really know what your app is supposed to do, but option number 2 - for my opinion - worth the hard work..
links:
intro to socket servers in php
intro to socket servers in java
Try adding a column to your users table regarding logged-in status (tinyint(1) since it's a MySQL table). It will be populated as either 0 (indicating logged out) or 1 (logged in). Upon logging in, the value needs to be set in the database as 1, and within your logout function, set back to 0. This way, you can use something similar to the below (which assumes the use of User objects):
<?php
$users = getUsers();
foreach($users as $user)
{
$display = "";
if($user->isLoggedIn())
{
$display .= '<img src="green.png" alt="Logged In" />';
}
else
{
$display .= '<img src="red.png" alt="Logged Out" />';
}
$display .= $user->getUsername().'<br />';
echo $display;
}
?>
The SQL command to alter your table:
ALTER TABLE gen_users ADD COLUMN loggedin TINYINT(1) DEFAULT 0;

Export Orders from Magento for shipment

I am working on an online store on the Magento platform and have hit a major roadblock: For some reason I cannot figure out how to export current orders (with shipping information/shipment type/etc). Does anyone have any suggestions? This seems as if it should be one of the most basic things for a system like this to do, but I have not been able to find out how.
Seeing as you want this for shipping you might want to ask whoever handles your shipping whether they have some sort of API so you can build/buy/download an appropriate shipping module and spare yourself the hassle of mucking about with CSV files.
If you really want a CSV file however I can show you how to create it. You didn't mention where this script will run so I'll assume it's an external script (which will make it easier to use with a cron job).
You want to do the following:
//External script - Load magento framework
require_once("C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\magento\app\Mage.php");
Mage::app('default');
$myOrder=Mage::getModel('sales/order');
$orders=Mage::getModel('sales/mysql4_order_collection');
//Optional filters you might want to use - more available operations in method _getConditionSql in Varien_Data_Collection_Db.
$orders->addFieldToFilter('total_paid',Array('gt'=>0)); //Amount paid larger than 0
$orders->addFieldToFilter('status',Array('eq'=>"processing")); //Status is "processing"
$allIds=$orders->getAllIds();
foreach($allIds as $thisId) {
$myOrder->reset()->load($thisId);
//echo "<pre>";
//print_r($myOrder);
//echo "</pre>";
//Some random fields
echo "'" . $myOrder->getBillingAddress()->getLastname() . "',";
echo "'" . $myOrder->getTotal_paid() . "',";
echo "'" . $myOrder->getShippingAddress()->getTelephone() . "',";
echo "'" . $myOrder->getPayment()->getCc_type() . "',";
echo "'" . $myOrder->getStatus() . "',";
echo "\r\n";
}
For the sake of brevity (and sanity) I haven't listed all the available order information. You can find out what fields are available by dumping the relevant objects and taking a look at their fields.
For example if you were to do print_r($myOrder->getBillingAddress()); you'd see fields like "address_type" and "lastname". You can use these with
$myOrder->getBillingAddress()->getAddress_type() and
$myOrder->getBillingAddress()->getLastname() respectively.
Edit:
Changed code according to craig.michael.morris's answer
I was in the process of implementing your solution and noticed that it was only returning the first values for all the foreign keys such as billing address, shipping address, payment etc...
This can be fixed by changing
$myOrder->load($thisId);
to
$myOrder->reset()->load($thisId);
You may also want to look at this extension: http://www.magentocommerce.com/extension/1158/manual-order-export
Also you can connect via soap: This example is set up for localhost and assumes you have set up a web services user and role under system>>web services in the admin.
<?php
$time = microtime();
$time = explode(' ', $time);
$time = $time[1] + $time[0];
$begintime = $time;
?>
<?php
ini_set('error_reporting', E_ALL);
ini_set('display_errors', 1);
// hostname
$host= '127.0.0.1';
// if store in /magento change /shop, if store in root remove /shop
$client= new SoapClient('http://'.$host.'/magento/index.php/api/soap/?wsdl');
// Can be added in Magento-Admin -> Web Services with role set to admin
$apiuser= 'soap';
// API key is password
$apikey = '******';
$sess_id= $client->login($apiuser, $apikey);
echo "<html>";
echo "<head>";
echo "<LINK REL=StyleSheet HREF=\"style.css\" TYPE=\"text/css\" MEDIA=screen>";
echo "</head>";
echo "<body>";
$result= $client->call($sess_id, 'sales_order.list', array(array('status'=>array('='=>'Pending'))));
echo '<pre>';
print_r($result);
echo '<pre>';
?>
<?php
// Let's see how long this took…
$time = microtime();
$time = explode(" ", $time);
$time = $time[1] + $time[0];
$endtime = $time;
$totaltime = ($endtime - $begintime);
echo '<br /><br /><em>This Magento SOAP API script took ' .$totaltime. ' seconds, precisely.</em>';
// ...and close the HTML document
echo "</body>";
echo "</html>";
?>
In case this helps any one, you can use the invoice table as a key. An invoice in magento with a auth+capture credit card setup means the money has come in. In our case we only needed a sql query to run in phpmyadmin that would export order numbers and invoice numbers for us to reconcile to check that the order export extension from xtento was working. This is what we used:
SELECT sales_flat_order.increment_id AS 'order', sales_flat_invoice.increment_id AS 'invoice'
FROM sales_flat_order
RIGHT JOIN sales_flat_invoice ON sales_flat_invoice.order_id = sales_flat_order.entity_id
WHERE sales_flat_invoice.updated_at >= "2011-07-01 00:00:00"
ORDER BY sales_flat_order.increment_id DESC
If the system doesn't support any direct way to export orders, you could create a view in the database that lists the orders you need to export. Then use something like phpMyAdmin to export the data from the view as CSV.
Saho's suggestion for using SOAP is great, but it may take a long time (Apache can only assign a limited CPU resource to tread to handle that request)
Suggest you to write a php script and then run it through terminal.
Sonam

Categories