*/ class ParTCP_Local_Id { public $fileSystem; public $dataDir; public $baseDir = ''; public $subdirDepth; public $subdirNameLength; public function __construct( $fileSystem, $dataDir ){ $this->fileSystem = $fileSystem; $this->dataDir = $dataDir; } public function set_base_dir( $baseDir = '', $estimatedTotal = NULL ){ $this->baseDir = rtrim( $baseDir, '/' ); if ( $estimatedTotal && function_exists('partcp_subdir_rules') ){ $rules = partcp_subdir_rules( $estimatedTotal ); $this->subdirDepth = $rules[0]; $this->subdirNameLength = $rules[1]; } } public function get_dir( $id = NULL ){ if ( ! $id ){ return 'participants_data'; } if ( ! empty( $this->subdirDepth ) ){ $parts = str_split( md5( $id ), $this->subdirNameLength ?? 2 ); $subdirs = implode( '/', array_slice( $parts, 0, $this->subdirDepth ) ); $id = "{$subdirs}/{$id}"; } return ( $this->baseDir ? "{$this->baseDir}/" : '' ) . "participants/{$id}"; } public function get_data( $id ){ $dir = $this->get_dir( $id ); $contents = $this->fileSystem->get_recent_contents( $dir, '[0-9]*' ); if ( $contents ){ $receipt = yaml_parse( $contents ); if ( ! empty( $receipt['Participant-Data'] ) ){ $data = $receipt['Participant-Data']; if ( ! empty( $data['attributes'] ) && is_string( $data['attributes'] ) ){ $data['attributes'] = json_decode( ptcp_local_decrypt( $data['attributes'] ), TRUE ); } } } $attr = $this->read_from_lookup_table( $id ); if ( $attr ){ if ( empty( $data ) ){ $data['id'] = $id; } $data['attributes'] = array_merge( $data['attributes'] ?? [], $attr ); } elseif ( empty( $data ) ){ return FALSE; } return $data; } public function registrations_exist(){ return $this->fileSystem->is_not_empty('participants'); } public function count_registrations(){ return $this->fileSystem->count_items( 'participants', '*registration*', TRUE ); } public function get_metadata(){ $result['registration_count'] = $this->count_registrations(); $file = "{$this->dataDir}/local_id/lut.csv"; if ( file_exists( $file ) ){ $spl = new \SplFileObject( $file ); while ( $spl->valid() ){ $spl->fgets(); } $result['lut_entries'] = $spl->key() - 1; $result['lut_modified_at'] = date( 'c', filemtime( $file ) ); $result['lut_size'] = filesize( $file ); $result['lut_columns'] = $this->read_from_lookup_table(); } return $result; } public function read_from_lookup_table( $ptcpId = NULL ){ $file = "{$this->dataDir}/local_id/lut.csv"; if ( ! file_exists( $file ) ){ return []; } $fh = fopen( $file, 'r' ); while ( ( $line = fgets( $fh ) ) !== FALSE ){ $data = str_getcsv( $line ); if ( empty( $colTitles ) ){ array_shift( $data ); $colTitles = $data; if ( ! $ptcpId ){ return $colTitles; } continue; } $id = array_shift( $data ); if ( $id == $ptcpId ){ return array_combine( $colTitles, $data ); } } return []; } public function store_lookup_table( $csvString, $idTitle, $options = [] ){ $delimiter = $options['delimiter'] ?? ','; $enclosure = $options['enclosure'] ?? '"'; $escape = $options['escape'] ?? '\\'; $lines = explode( "\n", trim( $csvString ) ); $lineCount = count( $lines ); if ( $lineCount > 999999 ){ return _('CSV data has too many lines'); } $fh = fopen( 'php://memory', 'w' ); for ( $i = 0; $i < $lineCount; $i++ ){ if ( strlen( $lines[ $i ] ) > 1024 ){ return sprintf( _('Line %s is too long'), $i + 1 ); } $arr = str_getcsv( $lines[ $i ], $delimiter, $enclosure, $escape ); if ( $i == 0 ){ $colTitles = $arr; $colCount = count( $colTitles ); $idCol = array_search( $idTitle, $colTitles ); if ( $idCol === FALSE ){ return _('Specified ID column does not exist'); } } if ( count( $arr ) != $colCount ){ return sprintf( _('Invalid number of columns in line %s'), $i + 1 ); } if ( $idCol ){ // ensure that id is first element $id = $arr[ $idCol ]; unset( $arr[ $idCol ] ); array_unshift( $arr, $id ); } fputcsv( $fh, $arr ); } rewind( $fh ); $data = stream_get_contents( $fh ); if ( ! $data ){ return -7; // Unknown error } $dir = "{$this->dataDir}/local_id"; if ( ! is_dir( $dir ) && ! mkdir( $dir, 0700, TRUE ) ){ return '!' . _('Could not create storage directory'); } $result = file_put_contents( "{$dir}/lut.csv", rtrim( $data ) ); if ( ! $result ){ return '!' . _('Could not store data'); } return TRUE; } } // end of file local_id.class.php