code: protected function copyRecursive( $src, $dst, $depth, Logger $logger )
      {
          if ( $depth == 0 )
          {
              return;
          }
  
          // Check if source file exists at all.
          if ( !is_file( $src ) && !is_dir( $src ) )
          {
              $logger->log( "$src is not a valid source.", Logger::WARNING );
              return;
          }
  
          // Skip non readable files in src directory
          if ( !is_readable( $src ) )
          {
              $logger->log( "$src is not readable, skipping.", Logger::WARNING );
              return;
          }
  
          // Destination file should not exist
          if ( is_file( $dst ) || is_dir( $dst ) )
          {
              $logger->log( "$dst already exists, and cannot be overwritten.", Logger::WARNING );
              return;
          }
  
          // Actually copy
          if ( is_dir( $src ) )
          {
              mkdir( $dst );
          }
          elseif ( is_file( $src ) )
          {
              copy( $src, $dst );
              return;
          }
  
          // Recurse into directory
          $dh = opendir( $src );
          while ( ( $file = readdir( $dh ) ) !== false )
          {
              if ( ( $file === '.' ) ||
                  ( $file === '..' ) )
              {
                  continue;
              }
  
              $this->copyRecursive(
                  $src . '/' . $file,
                  $dst . '/' . $file,
                  $depth - 1,
                  $logger
              );
          }
      }
docs: Copy files and directories recursively
  
  Copy files and directories recursively. I fone operation fails, a
  warning will be issued and the operation will be continued.
  
  A negative depth means infinite recursion. A depth of 1 means that the
  current files and directories are created, but no recursion is applied.
  
  @param string $src
  @param string $dst
  @param int $depth
  @param Logger $logger
  @return void