Вот версия @Lliver Wilkinson версии Swift 4 с некоторыми исправлениями и улучшенным форматированием кода:
import Foundation
import AVFoundation
class GSAudio: NSObject, AVAudioPlayerDelegate {
static let sharedInstance = GSAudio()
private override init() { }
var players: [URL: AVAudioPlayer] = [:]
var duplicatePlayers: [AVAudioPlayer] = []
func playSound(soundFileName: String) {
guard let bundle = Bundle.main.path(forResource: soundFileName, ofType: "aac") else { return }
let soundFileNameURL = URL(fileURLWithPath: bundle)
if let player = players[soundFileNameURL] { //player for sound has been found
if !player.isPlaying { //player is not in use, so use that one
player.prepareToPlay()
player.play()
} else { // player is in use, create a new, duplicate, player and use that instead
do {
let duplicatePlayer = try AVAudioPlayer(contentsOf: soundFileNameURL)
duplicatePlayer.delegate = self
//assign delegate for duplicatePlayer so delegate can remove the duplicate once it's stopped playing
duplicatePlayers.append(duplicatePlayer)
//add duplicate to array so it doesn't get removed from memory before finishing
duplicatePlayer.prepareToPlay()
duplicatePlayer.play()
} catch let error {
print(error.localizedDescription)
}
}
} else { //player has not been found, create a new player with the URL if possible
do {
let player = try AVAudioPlayer(contentsOf: soundFileNameURL)
players[soundFileNameURL] = player
player.prepareToPlay()
player.play()
} catch let error {
print(error.localizedDescription)
}
}
}
func playSounds(soundFileNames: [String]) {
for soundFileName in soundFileNames {
playSound(soundFileName: soundFileName)
}
}
func playSounds(soundFileNames: String...) {
for soundFileName in soundFileNames {
playSound(soundFileName: soundFileName)
}
}
func playSounds(soundFileNames: [String], withDelay: Double) { //withDelay is in seconds
for (index, soundFileName) in soundFileNames.enumerated() {
let delay = withDelay * Double(index)
let _ = Timer.scheduledTimer(timeInterval: delay, target: self, selector: #selector(playSoundNotification(_:)), userInfo: ["fileName": soundFileName], repeats: false)
}
}
@objc func playSoundNotification(_ notification: NSNotification) {
if let soundFileName = notification.userInfo?["fileName"] as? String {
playSound(soundFileName: soundFileName)
}
}
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
if let index = duplicatePlayers.index(of: player) {
duplicatePlayers.remove(at: index)
}
}
}
Можно создать новую группу и с апачским пользователем и с пользователем FTP как участники и затем сделать разрешение на папке загрузки 775. Это должно дать и апачским и пользователям FTP способность записать в файлы в папке, но помешать всем остальным изменять их.
Или по крайней мере 766.
7 = чтение +, запись + выполняется
6 = чтение + запись
Я пошел бы с ответом Ryan, если Вы действительно хотите сделать это.
В целом на *отклоняют среду, Вы всегда хотите допустить ошибку при выдаче как можно меньше полномочий.
9 раз из 10, 755 идеальное разрешение для этого - поскольку единственный пользователь со способностью изменить файлы будет веб-сервером. Измените это на 775 с Вашим пользователем FTP в группе, если ДЕЙСТВИТЕЛЬНО необходимо изменить это.
, Так как Вы плохо знакомы с php своим собственным подтверждением, вот полезная ссылка для улучшения безопасности Вашего сервиса загрузки: move_uploaded_file
Я добавлю, что при использовании SELinux, что необходимо удостовериться, контекст типа является tmp_t, можно выполнить это при помощи chcon утилиты
chcon-t tmp_t загрузки