Search code examples
phparraysfilterglob

Filter a php array to only elements that have a matching value to $name in $data


I have a php script getting all folders in a posts folder and making them into a list.

I have a $postinfo_str variable assigned to a json file for each folder which I am using to store post date and category/tag info etc in.

I also have a $pagetitle variable assigned to a title.php include file for each folder. So say I am on a "June 2018" archive page, the text in that file will be "June 2018". If I am on say a "Tutorials" category page, that will be the text in the title.php.

In the json file, I have:

{
     "Arraysortdate": "YYYYMMDD",
     "Month": "Month YYYY",
     "Category": ["cat1", "cat2", "etc"]
 }

I am ordering the array newest to oldest using krsort with Arraysortdate as key.

How do I filter the array using $pagetitle as input, finding if there is a match in $postinfo_str, and if there isn't, remove that folder from the array?

All I can seem to find regarding array sorting is where the info in the $pageinfo_str is basically the array and so by that, the $title is the input and the output is the matching text from the $postinfo_str, whereas I want the output to be the folders that only have the matching text in the $postinfo_str to what the input ($pagetitle) is.

Here is my code I have.. Keep in mind this is flat file, I do not want a database to achieve this. See comments if you want an explaination.

<?php 

	$BASE_PATH = '/path/to/public_html';
	
	// initial array containing the dirs
	    $dirs = glob($BASE_PATH.'/testblog/*/posts/*', GLOB_ONLYDIR);

	// new array with date as key
	    $dirinfo_arr = [];
	    foreach ($dirs as $cdir) {

		// get current page title from file
		    $pagetitle = file_get_contents("includes/title.php");
	
		// get date & post info from file
		    $dirinfo_str = file_get_contents("$cdir/includes/post-info.json");
		    $dirinfo = json_decode($dirinfo_str, TRUE);

		// add current directory to the info array
		    $dirinfo['dir'] = $cdir;
		// add current dir to new array where date is the key
		    $dirinfo_arr[$dirinfo['Arraysortdate']] = $dirinfo;
	}
	// now we sort the new array
	    krsort($dirinfo_arr);

	    foreach($dirinfo_arr as $key=>$dir) {
	    	$dirpath = $dir['dir'];
		$dirpath = str_replace('/path/to/public_html/', '', $dirpath);

?>


       <!--HTML HERE SUCH AS--!>
       
           <a href="<?=$dirpath;?>"> TEXT </a><br>

<?php
};
?>



Solution

  • I have difficulties following your problem description. Your code example is slightly confusing. It appears to load the same global includes/title.php for each directory. Meaning, the value of $pagetitle should be the same every iteration. If this is intended, you should probably move that line right outside the loop. If the file contains actual php code, you should probably use

    $pagetitle = include 'includes/title.php'; 
    

    or something similar. If it doesn't, you should probably name it title.txt. If it is not one global file, you should probably add the path to the file_get_contents/include as well. (However, why wouldn't you just add the title in the json struct?)

    I'm under the assumption that this happened by accident when trying to provide a minimal code example (?) ... In any case, my answer won't be the perfect answer, but it hopefully can be adapted once understood ;o)

    If you only want elements in your array, that fulfill certain properties, you have essentially two choices:

    1. don't put those element in (mostly your code)

      foreach ($dirs as $cdir) {
      
          // get current page title from file
          $pagetitle = file_get_contents("includes/title.php");
      
          // get date & post info from file
          $dirinfo_str = file_get_contents("$cdir/includes/post-info.json");
          $dirinfo = json_decode($dirinfo_str, TRUE);
      
          // add current directory to the info array
          $dirinfo['dir'] = $cdir;
          // add current dir to new array where date is the key
      
       // ------------ NEW --------------
          $filtercat = 'cat1';
          if(!in_array($filtercat, $dirinfo['Category'])) {
               continue;
          }
       // -------------------------------
      
          $dirinfo_arr[$dirinfo['Arraysortdate']] = $dirinfo;
      
    2. array_filter the array afterwards, by providing a anonymous function

       // ----- before cycling through $dirinfo_arr for output
       $filtercat = 'cat1';
       $filterfunc = function($dirinfo) use ($filtercat) {
           return in_array($filtercat, $dirinfo['Category']));
       }
      
       $dirinfo_arr = array_filter($dirinfo_arr, $filterfunc);
      

      you should read up about anonymous functions and how you provide local vars to them, to ease the pain. maybe your use case is bettersuited for array_reduce, which is similar, except you can determine the output of your "filter".

    $new = array_filter($array, $func), is just a fancy way of writing:

    $new = [];
    foreach($array as $key => $value) {
        if($func($value)) {
            $new[$key] = $value;
        }
    }
    

    update 1

    in my code samples, you could replace in_array($filtercat, $dirinfo['Category']) with in_array($pagetitle, $dirinfo) - if you want to match on anything that's in the json-struct (base level) - or with ($pagetitle == $dirinfo['Month']) if you just want to match the month.

    update 2

    I understand, that you're probably just starting with php or even programming, so the concept of some "huge database" may be frightening. But tbh, the filesystem is - from a certain point of view - a database as well. However, it usually is quite slow in comparison, it also doesn't provide many features.

    In the long run, I would strongly suggest using a database. If you don't like the idea of putting your data in "some database server", use sqlite. However, there is a learning curve involved, if you never had to deal with databases before. In the long run it will be time worth spending, because it simplifys so many things.