How to count users from Firebase with PHP (Laravel 5.8) - php

I'm trying to figure out how to count all registered users from the Firebase. I've only implemented the Firebase authentication and have not mannualy created a database.
I can't find a way to count or even get them from Firebase.
$serviceAccount = ServiceAccount::fromJsonFile(config_path('path-to-file.json'));
$firebase = (new Factory())
->withServiceAccount($serviceAccount)
->create();
$database = $firebase->getDatabase();
I've got a connection with the code above.
Also I tried to use the auth helper like:
$auth = $firebase->getAuth();
$users = $auth->listUsers($defaultMaxResults = 1000, $defaultBatchSize = 1000);
But the thing I only managed with this was getting the current user.
Anyone knows how to count all users / get them?

👋 Hi, maintainer of the SDK you're using here :).
There is currently (as of 2019-08-29 and as far as I know) no way to directly get the number of registered users in a Firebase project except through iterating through all of them and counting them manually.
The fastest way to do this would be by using
$users = $auth->listUsers();
$userCount = iterator_count($users);
We have to use iterator_count here because Auth::listUsers() returns a Generator that behaves differently than the "usual" array: instead of fetching all the users at once, it will fetch the next batch only when we "need" it.
There are methods to convert an iterator to an array (iterator_to_array()) and to count all items of an iterator (iterator_count()), but under the hood, they will load all users into memory, which can become really expensive if you have thousands or hundreds of thousands of users.
For that reason, I would recommend not using iterator_to_array() but foreach when you want to work with the user records directly:
foreach ($users as $user) {
/** #var \Kreait\Firebase\Auth\UserRecord $user */
echo $user->uid;
}
as well as using iterator_count() only sparingly and cache the result when you have it.
PS: Did you know that there's now a Laravel Package for this SDK as well? 😅

Related

How to get child count of a parent from Firebase using PHP?

I'm developing an application like facebook to create posts and users can comment and like to the posts. I use firebase realtime database to store likes and comments data for posts. Follow the image below,
Now I need to get the posts to ascending order by comments count and likes count. How can I do this using PHP ?
You can find an unofficial Admin SDK for PHP at https://github.com/kreait/firebase-php that makes this fairly easy.
Once installed and set up, you can do this:
<?php
require 'vendor/autoload.php';
use Kreait\Firebase\Factory;
use Kreait\Firebase\ServiceAccount;
$serviceAccount = ServiceAccount::fromJsonFile('/path/to/credentials.json');
$firebase = (new Factory())
->withServiceAccount($serviceAccount)
->create();
$db = $firebase->getDatabase();
echo count($db->getReference('path/to/comments')->shallow()->getValue());
I don't know a more comfortable way to do it in PHP 😇 (Disclaimer: I created the SDK 😅)

Retrieving list of sub-OUs within a specific OU using ADLDAP2

I'm working on a project using PHP Adldap2 Library (https://github.com/Adldap2/Adldap2) and I need to retrieve a list of sub-OUs within a specific OU from Active Directory.
That's what I tried:
$ad->search()
->whereEquals(
ActiveDirectory::OBJECT_CATEGORY,
ActiveDirectory::ORGANIZATIONAL_UNIT_LONG
)
->whereEndsWith('dn', 'OU=myou,DC=mycompany,DC=com')
->get();
While the first filter works and retrieves all OUs, the second doesn't and returns an empty array. I also tried using 'distinguishedname' instead of 'dn' in whereEndsWith, with the same result.
How can this be done?
After doing some research and experimentation I came up with this code:
$config = Adldap::getConfiguration();
$baseDn = new Adldap\Objects\DistinguishedName($config->getBaseDn());
$departmentsDn = $baseDn->addOu('myou');
$search = Adldap::search()->setDn($departmentsDn->get());
$entries = $search->whereEquals(ActiveDirectory::OBJECT_CATEGORY, ActiveDirectory::ORGANIZATIONAL_UNIT_LONG)->get();
I'm not sure if it is the best solution but it works.
PS: I'm using Laravel adldap facade that's why adldap calls are static.

Where to instantiate objects for a collection if the DataMapper is only for transfer/exchange of data?

Since the DataMapper is supposed to be for the exchange/transfer of data between objects and the relational database I would get a user like this
$user = $this->entityFactory->build('User');
$userMapper = $this->mapperFactory->build('User');
$user->setId(43);
$userMapper->fetch($user);
That works fine because I can create the User object outside of the mapper and pass it in but what do I do when I am getting a collection/list of objects?
Creating the empty objects outside of the mapper first just does not seem correct and would surely cause some problems so what is the best way to do it?
Thanks.
I don't know if this question is still in your mind, however let me give you an answer to this. In principle the first step is the same
$userCollection = $this->entityFactory->build('UserCollection');
$userCollectionMapper = $this->mapperFactory->build('UserCollection');
$user = $this->entityFactory->build('User');
$user->setId(43);
$userCollection->add($user);
$userCollectionMapper->fetch($userCollection);
So the userObject would function here as an searchObject for the collectionMapper (like teresko proposed in an older thread). Your CollectionMapper would retrieve the data from the database and i prefer to use something like
//returns new User object
$newUser = $userCollection->newUser();
//populate user object with DB entry
$userCollectionMapper->populate($newUser,$DBresponse);
//add to collection
$userCollection->add($newUser);
Of course there would be a loop before that looping through the found lines in the database and you would have to clear the list of user objects before adding the results.
So this is the way i would deal with the problem. Hope it helps.

What is the most efficient way to include an API on a page?

The website I am re-building uses its own API to gather most of its content (e.g. http://api.example.com/). Although the answer to this is quite self explanatory, I just want to be sure before I proceed.
As far as I am aware, I have 2 (potentially 3) options of loading the data from the api via PHP.
I can load the classes into the document and gather the data manually from the class (probably the best way, but requires more code and if changes are made to the class, I have to alter the pages and the API document instead of just changing the API)
Use file_get_contents('http://api.example.com/search'). This would be the easiest way but it requires another HTTP request and I assume it is slightly slower.
Lastly, if this this possible then I think it will be the best way, but to my knowledge I do not think it is possible. Read the file locally with $_GET parameters implemented and obtain the results this way.
EXAMPLES
1.
// Include the mysql connections
require_once($_SERVER['DOCUMENT_ROOT'].'/scripts/php/_connections/mysql.company.php');
// Include the Classes (Company and Facebook)
require_once($_SERVER['DOCUMENT_ROOT'].'/scripts/php/_classes/class.company.php');
require_once($_SERVER['DOCUMENT_ROOT'].'/scripts/php/_classes/class.mysql.php');
require_once($_SERVER['DOCUMENT_ROOT'].'/scripts/php/_facebook/config.facebook.php');
require_once($_SERVER['DOCUMENT_ROOT'].'/scripts/php/_facebook/class.facebook.php');
// Create the objects (Company, MySQL, Memcache and Facebook)
$memcache = new memcache;
$facebook = new Facebook($facebook_config);
$mysql = new mysql($memcache);
$company = new company($_DATABASES,$_CONNECTIONS,$mysql,$memache,$facebook);
// CALL THE RELEVANT CLASS METHOD HERE
2.
Something like (ignore mistakes)
$API = 'http://api.example.com/search?query=test'
$data = file_get_contents(url_encode($API));
3.
Not sure if this is possible, please note I do NOT want to use the last method
$parameters = array(
'method'=>'GET',
'parameters'=>array(
'function'=>'search',
'query'=>'test'
)
);
$API = some_cool_function('/_scripts/api/2/api/api.php',$parameters);
// I DO NOT WANT TO DO THIS FOR CERTAIN REASONS:
$_GET=array(
'function'=>'search',
'query'=>'test'
);
$data = include('/_scripts/api/2/api/api.php');
Normally I'd say the 1st option - with Oauth etc that's in place in most API's these days I'm sure a nicely wrapped class setup would be much easier to work with.

Updating Zend_Auth_Storage after edit users profile

I have following situation:
I have loged user, standard authentication with DB table
$authAdapter = new Zend_Auth_Adapter_DbTable(Zend_Db_Table::getDefaultAdapter());
$authAdapter->setTableName('users');
$authAdapter->setIdentityColumn('user_name');
$authAdapter->setCredentialColumn('password');
When user edits his profile, I save it into Db, but I need to update also storage (using standard Zend_Auth_Storage_Session). Is there any easy way how to do it? Many thanks.
$user = Zend_Auth::getInstance()->getIdentity();
$user->newValue = 'new value';
Assuming you are updating the session data in the same statement you are updating the database in there is no need to call the db again.
Your best bet would be to not use Zend_Auth's storage to hold information that's likely to change - by default it only holds the identity (for good reason). I'd probably make a User class that wrapped all the Auth, ACL (and probably profile) functionality that uses a static get_current() method to load the user stashed in the session. This bypasses all the consistency issues you run into when stuffing it into the session as well as giving you a single point from which to implement caching if/when you actually need the performance boost.
I have done it like this, it works, but I don't know if there is not some better way,how to do it
$user_data = User::getUser($user_id)->toArray();
unset($user_data['password']);
$std_user = new stdClass();
foreach ($user_data as $key => $value)
{
$std_user->$key = $value;
}
$auth = Zend_Auth::getInstance();
$auth->getStorage()->write($std_user);

Categories